2013-12-17 19:21:03 -07:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package imports
|
|
|
|
|
|
|
|
import (
|
2018-11-20 14:20:01 -07:00
|
|
|
"bytes"
|
2018-04-24 14:05:29 -06:00
|
|
|
"context"
|
2013-12-17 19:21:03 -07:00
|
|
|
"fmt"
|
|
|
|
"go/ast"
|
|
|
|
"go/build"
|
|
|
|
"go/parser"
|
|
|
|
"go/token"
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
"io/ioutil"
|
2013-12-17 19:21:03 -07:00
|
|
|
"os"
|
2018-11-20 14:20:01 -07:00
|
|
|
"os/exec"
|
2013-12-17 19:21:03 -07:00
|
|
|
"path"
|
|
|
|
"path/filepath"
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
"sort"
|
2018-07-09 10:01:45 -06:00
|
|
|
"strconv"
|
2013-12-17 19:21:03 -07:00
|
|
|
"strings"
|
|
|
|
"sync"
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
"time"
|
2019-01-10 10:51:27 -07:00
|
|
|
"unicode"
|
|
|
|
"unicode/utf8"
|
2013-12-17 19:21:03 -07:00
|
|
|
|
2015-01-08 19:32:51 -07:00
|
|
|
"golang.org/x/tools/go/ast/astutil"
|
2018-11-20 14:20:01 -07:00
|
|
|
"golang.org/x/tools/go/packages"
|
2018-09-18 13:06:34 -06:00
|
|
|
"golang.org/x/tools/internal/gopathwalk"
|
2013-12-17 19:21:03 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
// importToGroup is a list of functions which map from an import path to
|
|
|
|
// a group number.
|
2019-05-06 13:37:46 -06:00
|
|
|
var importToGroup = []func(env *ProcessEnv, importPath string) (num int, ok bool){
|
|
|
|
func(env *ProcessEnv, importPath string) (num int, ok bool) {
|
|
|
|
if env.LocalPrefix == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, p := range strings.Split(env.LocalPrefix, ",") {
|
2018-03-13 15:48:25 -06:00
|
|
|
if strings.HasPrefix(importPath, p) || strings.TrimSuffix(p, "/") == importPath {
|
2017-12-23 01:05:04 -07:00
|
|
|
return 3, true
|
|
|
|
}
|
2016-07-21 19:35:08 -06:00
|
|
|
}
|
|
|
|
return
|
|
|
|
},
|
2019-05-06 13:37:46 -06:00
|
|
|
func(_ *ProcessEnv, importPath string) (num int, ok bool) {
|
2013-12-17 19:21:03 -07:00
|
|
|
if strings.HasPrefix(importPath, "appengine") {
|
|
|
|
return 2, true
|
|
|
|
}
|
|
|
|
return
|
|
|
|
},
|
2019-05-06 13:37:46 -06:00
|
|
|
func(_ *ProcessEnv, importPath string) (num int, ok bool) {
|
2013-12-17 19:21:03 -07:00
|
|
|
if strings.Contains(importPath, ".") {
|
|
|
|
return 1, true
|
|
|
|
}
|
|
|
|
return
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
func importGroup(env *ProcessEnv, importPath string) int {
|
2013-12-17 19:21:03 -07:00
|
|
|
for _, fn := range importToGroup {
|
2019-05-06 13:37:46 -06:00
|
|
|
if n, ok := fn(env, importPath); ok {
|
2013-12-17 19:21:03 -07:00
|
|
|
return n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2019-07-30 12:00:02 -06:00
|
|
|
type ImportFixType int
|
2019-06-28 13:19:56 -06:00
|
|
|
|
|
|
|
const (
|
2019-07-30 12:00:02 -06:00
|
|
|
AddImport ImportFixType = iota
|
|
|
|
DeleteImport
|
|
|
|
SetImportName
|
2019-06-28 13:19:56 -06:00
|
|
|
)
|
|
|
|
|
2019-07-30 12:00:02 -06:00
|
|
|
type ImportFix struct {
|
|
|
|
// StmtInfo represents the import statement this fix will add, remove, or change.
|
|
|
|
StmtInfo ImportInfo
|
|
|
|
// IdentName is the identifier that this fix will add or remove.
|
|
|
|
IdentName string
|
|
|
|
// FixType is the type of fix this is (AddImport, DeleteImport, SetImportName).
|
|
|
|
FixType ImportFixType
|
2019-06-28 13:19:56 -06:00
|
|
|
}
|
|
|
|
|
2019-07-30 12:00:02 -06:00
|
|
|
// An ImportInfo represents a single import statement.
|
|
|
|
type ImportInfo struct {
|
|
|
|
ImportPath string // import path, e.g. "crypto/rand".
|
|
|
|
Name string // import name, e.g. "crand", or "" if none.
|
2017-05-12 14:54:58 -06:00
|
|
|
}
|
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// A packageInfo represents what's known about a package.
|
2016-05-25 17:35:48 -06:00
|
|
|
type packageInfo struct {
|
2019-01-16 14:24:49 -07:00
|
|
|
name string // real package name, if known.
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
exports map[string]bool // known exports.
|
2016-05-25 17:35:48 -06:00
|
|
|
}
|
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// parseOtherFiles parses all the Go files in srcDir except filename, including
|
|
|
|
// test files if filename looks like a test.
|
|
|
|
func parseOtherFiles(fset *token.FileSet, srcDir, filename string) []*ast.File {
|
2018-11-20 14:20:01 -07:00
|
|
|
// This could use go/packages but it doesn't buy much, and it fails
|
|
|
|
// with https://golang.org/issue/26296 in LoadFiles mode in some cases.
|
2016-05-25 17:35:48 -06:00
|
|
|
considerTests := strings.HasSuffix(filename, "_test.go")
|
|
|
|
|
|
|
|
fileBase := filepath.Base(filename)
|
|
|
|
packageFileInfos, err := ioutil.ReadDir(srcDir)
|
|
|
|
if err != nil {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
return nil
|
2017-12-08 07:26:14 -07:00
|
|
|
}
|
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
var files []*ast.File
|
2016-05-25 17:35:48 -06:00
|
|
|
for _, fi := range packageFileInfos {
|
|
|
|
if fi.Name() == fileBase || !strings.HasSuffix(fi.Name(), ".go") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !considerTests && strings.HasSuffix(fi.Name(), "_test.go") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
f, err := parser.ParseFile(fset, filepath.Join(srcDir, fi.Name()), nil, 0)
|
2016-05-25 17:35:48 -06:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
files = append(files, f)
|
|
|
|
}
|
2016-05-25 17:35:48 -06:00
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
return files
|
|
|
|
}
|
|
|
|
|
|
|
|
// addGlobals puts the names of package vars into the provided map.
|
|
|
|
func addGlobals(f *ast.File, globals map[string]bool) {
|
|
|
|
for _, decl := range f.Decls {
|
|
|
|
genDecl, ok := decl.(*ast.GenDecl)
|
|
|
|
if !ok {
|
|
|
|
continue
|
2016-05-25 17:35:48 -06:00
|
|
|
}
|
2017-05-12 14:54:58 -06:00
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
for _, spec := range genDecl.Specs {
|
|
|
|
valueSpec, ok := spec.(*ast.ValueSpec)
|
|
|
|
if !ok {
|
|
|
|
continue
|
2017-05-12 14:54:58 -06:00
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
globals[valueSpec.Names[0].Name] = true
|
2017-05-12 14:54:58 -06:00
|
|
|
}
|
2016-05-25 17:35:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// collectReferences builds a map of selector expressions, from
|
|
|
|
// left hand side (X) to a set of right hand sides (Sel).
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
func collectReferences(f *ast.File) references {
|
|
|
|
refs := references{}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
|
2017-12-08 07:26:14 -07:00
|
|
|
var visitor visitFn
|
|
|
|
visitor = func(node ast.Node) ast.Visitor {
|
|
|
|
if node == nil {
|
|
|
|
return visitor
|
|
|
|
}
|
|
|
|
switch v := node.(type) {
|
|
|
|
case *ast.SelectorExpr:
|
|
|
|
xident, ok := v.X.(*ast.Ident)
|
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if xident.Obj != nil {
|
2019-01-03 11:53:54 -07:00
|
|
|
// If the parser can resolve it, it's not a package ref.
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if !ast.IsExported(v.Sel.Name) {
|
|
|
|
// Whatever this is, it's not exported from a package.
|
2017-12-08 07:26:14 -07:00
|
|
|
break
|
|
|
|
}
|
|
|
|
pkgName := xident.Name
|
|
|
|
r := refs[pkgName]
|
|
|
|
if r == nil {
|
|
|
|
r = make(map[string]bool)
|
|
|
|
refs[pkgName] = r
|
|
|
|
}
|
2019-01-03 11:53:54 -07:00
|
|
|
r[v.Sel.Name] = true
|
2017-12-08 07:26:14 -07:00
|
|
|
}
|
|
|
|
return visitor
|
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
ast.Walk(visitor, f)
|
|
|
|
return refs
|
2017-12-08 07:26:14 -07:00
|
|
|
}
|
|
|
|
|
2019-07-02 12:55:42 -06:00
|
|
|
// collectImports returns all the imports in f.
|
|
|
|
// Unnamed imports (., _) and "C" are ignored.
|
2019-07-30 12:00:02 -06:00
|
|
|
func collectImports(f *ast.File) []*ImportInfo {
|
|
|
|
var imports []*ImportInfo
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
for _, imp := range f.Imports {
|
|
|
|
var name string
|
|
|
|
if imp.Name != nil {
|
|
|
|
name = imp.Name.Name
|
|
|
|
}
|
|
|
|
if imp.Path.Value == `"C"` || name == "_" || name == "." {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
path := strings.Trim(imp.Path.Value, `"`)
|
2019-07-30 12:00:02 -06:00
|
|
|
imports = append(imports, &ImportInfo{
|
|
|
|
Name: name,
|
|
|
|
ImportPath: path,
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return imports
|
|
|
|
}
|
2013-12-17 19:21:03 -07:00
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// findMissingImport searches pass's candidates for an import that provides
|
|
|
|
// pkg, containing all of syms.
|
2019-07-30 12:00:02 -06:00
|
|
|
func (p *pass) findMissingImport(pkg string, syms map[string]bool) *ImportInfo {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
for _, candidate := range p.candidates {
|
2019-07-30 12:00:02 -06:00
|
|
|
pkgInfo, ok := p.knownPackages[candidate.ImportPath]
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
2019-01-16 14:24:49 -07:00
|
|
|
if p.importIdentifier(candidate) != pkg {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
continue
|
|
|
|
}
|
2013-12-17 19:21:03 -07:00
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
allFound := true
|
|
|
|
for right := range syms {
|
|
|
|
if !pkgInfo.exports[right] {
|
|
|
|
allFound = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if allFound {
|
|
|
|
return candidate
|
|
|
|
}
|
2016-04-13 15:57:13 -06:00
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
// references is set of references found in a Go file. The first map key is the
|
|
|
|
// left hand side of a selector expression, the second key is the right hand
|
|
|
|
// side, and the value should always be true.
|
|
|
|
type references map[string]map[string]bool
|
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// A pass contains all the inputs and state necessary to fix a file's imports.
|
|
|
|
// It can be modified in some ways during use; see comments below.
|
|
|
|
type pass struct {
|
|
|
|
// Inputs. These must be set before a call to load, and not modified after.
|
2018-11-20 14:20:01 -07:00
|
|
|
fset *token.FileSet // fset used to parse f and its siblings.
|
|
|
|
f *ast.File // the file being fixed.
|
|
|
|
srcDir string // the directory containing f.
|
2019-05-06 13:37:46 -06:00
|
|
|
env *ProcessEnv // the environment to use for go commands, etc.
|
2018-11-20 14:20:01 -07:00
|
|
|
loadRealPackageNames bool // if true, load package names from disk rather than guessing them.
|
|
|
|
otherFiles []*ast.File // sibling files.
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
|
|
|
|
// Intermediate state, generated by load.
|
2019-07-30 12:00:02 -06:00
|
|
|
existingImports map[string]*ImportInfo
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
allRefs references
|
|
|
|
missingRefs references
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
|
|
|
|
// Inputs to fix. These can be augmented between successive fix calls.
|
2018-11-20 14:20:01 -07:00
|
|
|
lastTry bool // indicates that this is the last call and fix should clean up as best it can.
|
2019-07-30 12:00:02 -06:00
|
|
|
candidates []*ImportInfo // candidate imports in priority order.
|
2018-11-20 14:20:01 -07:00
|
|
|
knownPackages map[string]*packageInfo // information about all known packages.
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// loadPackageNames saves the package names for everything referenced by imports.
|
2019-07-30 12:00:02 -06:00
|
|
|
func (p *pass) loadPackageNames(imports []*ImportInfo) error {
|
2019-06-28 14:21:07 -06:00
|
|
|
if p.env.Debug {
|
|
|
|
p.env.Logf("loading package names for %v packages", len(imports))
|
|
|
|
defer func() {
|
|
|
|
p.env.Logf("done loading package names for %v packages", len(imports))
|
|
|
|
}()
|
|
|
|
}
|
2018-11-20 14:20:01 -07:00
|
|
|
var unknown []string
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
for _, imp := range imports {
|
2019-07-30 12:00:02 -06:00
|
|
|
if _, ok := p.knownPackages[imp.ImportPath]; ok {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
continue
|
|
|
|
}
|
2019-07-30 12:00:02 -06:00
|
|
|
unknown = append(unknown, imp.ImportPath)
|
2018-11-20 14:20:01 -07:00
|
|
|
}
|
|
|
|
|
2019-07-03 13:23:05 -06:00
|
|
|
names, err := p.env.GetResolver().loadPackageNames(unknown, p.srcDir)
|
2018-11-20 14:20:01 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
|
|
|
|
for path, name := range names {
|
|
|
|
p.knownPackages[path] = &packageInfo{
|
|
|
|
name: name,
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
exports: map[string]bool{},
|
|
|
|
}
|
|
|
|
}
|
2018-11-20 14:20:01 -07:00
|
|
|
return nil
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 14:24:49 -07:00
|
|
|
// importIdentifier returns the identifier that imp will introduce. It will
|
|
|
|
// guess if the package name has not been loaded, e.g. because the source
|
|
|
|
// is not available.
|
2019-07-30 12:00:02 -06:00
|
|
|
func (p *pass) importIdentifier(imp *ImportInfo) string {
|
|
|
|
if imp.Name != "" {
|
|
|
|
return imp.Name
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
2019-07-30 12:00:02 -06:00
|
|
|
known := p.knownPackages[imp.ImportPath]
|
2019-01-16 14:24:49 -07:00
|
|
|
if known != nil && known.name != "" {
|
|
|
|
return known.name
|
|
|
|
}
|
2019-07-30 12:00:02 -06:00
|
|
|
return importPathToAssumedName(imp.ImportPath)
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
2016-04-13 15:57:13 -06:00
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// load reads in everything necessary to run a pass, and reports whether the
|
2018-12-18 12:53:56 -07:00
|
|
|
// file already has all the imports it needs. It fills in p.missingRefs with the
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// file's missing symbols, if any, or removes unused imports if not.
|
2019-07-30 12:00:02 -06:00
|
|
|
func (p *pass) load() ([]*ImportFix, bool) {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
p.knownPackages = map[string]*packageInfo{}
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
p.missingRefs = references{}
|
2019-07-30 12:00:02 -06:00
|
|
|
p.existingImports = map[string]*ImportInfo{}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
|
|
|
|
// Load basic information about the file in question.
|
2018-12-18 12:53:56 -07:00
|
|
|
p.allRefs = collectReferences(p.f)
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
|
|
|
|
// Load stuff from other files in the same package:
|
|
|
|
// global variables so we know they don't need resolving, and imports
|
|
|
|
// that we might want to mimic.
|
|
|
|
globals := map[string]bool{}
|
|
|
|
for _, otherFile := range p.otherFiles {
|
2018-12-10 11:43:31 -07:00
|
|
|
// Don't load globals from files that are in the same directory
|
|
|
|
// but a different package. Using them to suggest imports is OK.
|
|
|
|
if p.f.Name.Name == otherFile.Name.Name {
|
|
|
|
addGlobals(otherFile, globals)
|
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
p.candidates = append(p.candidates, collectImports(otherFile)...)
|
|
|
|
}
|
2016-05-25 17:35:48 -06:00
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// Resolve all the import paths we've seen to package names, and store
|
|
|
|
// f's imports by the identifier they introduce.
|
|
|
|
imports := collectImports(p.f)
|
2019-01-16 14:24:49 -07:00
|
|
|
if p.loadRealPackageNames {
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
err := p.loadPackageNames(append(imports, p.candidates...))
|
|
|
|
if err != nil {
|
2019-05-06 13:37:46 -06:00
|
|
|
if p.env.Debug {
|
2019-06-28 14:21:07 -06:00
|
|
|
p.env.Logf("loading package names: %v", err)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
2019-06-28 13:19:56 -06:00
|
|
|
return nil, false
|
2019-01-17 13:27:01 -07:00
|
|
|
}
|
2019-01-16 14:24:49 -07:00
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
for _, imp := range imports {
|
|
|
|
p.existingImports[p.importIdentifier(imp)] = imp
|
|
|
|
}
|
|
|
|
|
2018-12-18 12:53:56 -07:00
|
|
|
// Find missing references.
|
|
|
|
for left, rights := range p.allRefs {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
if globals[left] {
|
|
|
|
continue
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
2018-12-18 12:53:56 -07:00
|
|
|
_, ok := p.existingImports[left]
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
if !ok {
|
2018-12-18 12:53:56 -07:00
|
|
|
p.missingRefs[left] = rights
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
continue
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
2018-12-18 12:53:56 -07:00
|
|
|
if len(p.missingRefs) != 0 {
|
2019-06-28 13:19:56 -06:00
|
|
|
return nil, false
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
2013-12-17 19:21:03 -07:00
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
return p.fix()
|
|
|
|
}
|
|
|
|
|
|
|
|
// fix attempts to satisfy missing imports using p.candidates. If it finds
|
2019-06-28 13:19:56 -06:00
|
|
|
// everything, or if p.lastTry is true, it updates fixes to add the imports it found,
|
|
|
|
// delete anything unused, and update import names, and returns true.
|
2019-07-30 12:00:02 -06:00
|
|
|
func (p *pass) fix() ([]*ImportFix, bool) {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// Find missing imports.
|
2019-07-30 12:00:02 -06:00
|
|
|
var selected []*ImportInfo
|
2018-12-18 12:53:56 -07:00
|
|
|
for left, rights := range p.missingRefs {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
if imp := p.findMissingImport(left, rights); imp != nil {
|
|
|
|
selected = append(selected, imp)
|
2015-08-07 09:16:12 -06:00
|
|
|
}
|
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
|
2018-12-18 12:53:56 -07:00
|
|
|
if !p.lastTry && len(selected) != len(p.missingRefs) {
|
2019-06-28 13:19:56 -06:00
|
|
|
return nil, false
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Found everything, or giving up. Add the new imports and remove any unused.
|
2019-07-30 12:00:02 -06:00
|
|
|
var fixes []*ImportFix
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
for _, imp := range p.existingImports {
|
2018-12-18 12:53:56 -07:00
|
|
|
// We deliberately ignore globals here, because we can't be sure
|
|
|
|
// they're in the same package. People do things like put multiple
|
|
|
|
// main packages in the same directory, and we don't want to
|
|
|
|
// remove imports if they happen to have the same name as a var in
|
|
|
|
// a different package.
|
|
|
|
if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok {
|
2019-07-30 12:00:02 -06:00
|
|
|
fixes = append(fixes, &ImportFix{
|
|
|
|
StmtInfo: *imp,
|
|
|
|
IdentName: p.importIdentifier(imp),
|
|
|
|
FixType: DeleteImport,
|
2019-06-28 13:19:56 -06:00
|
|
|
})
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// An existing import may need to update its import name to be correct.
|
2019-07-30 12:00:02 -06:00
|
|
|
if name := p.importSpecName(imp); name != imp.Name {
|
|
|
|
fixes = append(fixes, &ImportFix{
|
|
|
|
StmtInfo: ImportInfo{
|
|
|
|
Name: name,
|
|
|
|
ImportPath: imp.ImportPath,
|
2019-06-28 13:19:56 -06:00
|
|
|
},
|
2019-07-30 12:00:02 -06:00
|
|
|
IdentName: p.importIdentifier(imp),
|
|
|
|
FixType: SetImportName,
|
2019-06-28 13:19:56 -06:00
|
|
|
})
|
2015-08-07 09:16:12 -06:00
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
2018-11-20 13:24:09 -07:00
|
|
|
|
2018-11-20 14:20:01 -07:00
|
|
|
for _, imp := range selected {
|
2019-07-30 12:00:02 -06:00
|
|
|
fixes = append(fixes, &ImportFix{
|
|
|
|
StmtInfo: ImportInfo{
|
|
|
|
Name: p.importSpecName(imp),
|
|
|
|
ImportPath: imp.ImportPath,
|
2019-06-28 13:19:56 -06:00
|
|
|
},
|
2019-07-30 12:00:02 -06:00
|
|
|
IdentName: p.importIdentifier(imp),
|
|
|
|
FixType: AddImport,
|
2019-06-28 13:19:56 -06:00
|
|
|
})
|
2018-11-20 14:20:01 -07:00
|
|
|
}
|
|
|
|
|
2019-06-28 13:19:56 -06:00
|
|
|
return fixes, true
|
|
|
|
}
|
|
|
|
|
|
|
|
// importSpecName gets the import name of imp in the import spec.
|
|
|
|
//
|
|
|
|
// When the import identifier matches the assumed import name, the import name does
|
|
|
|
// not appear in the import spec.
|
2019-07-30 12:00:02 -06:00
|
|
|
func (p *pass) importSpecName(imp *ImportInfo) string {
|
2019-06-28 13:19:56 -06:00
|
|
|
// If we did not load the real package names, or the name is already set,
|
|
|
|
// we just return the existing name.
|
2019-07-30 12:00:02 -06:00
|
|
|
if !p.loadRealPackageNames || imp.Name != "" {
|
|
|
|
return imp.Name
|
2019-06-28 13:19:56 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
ident := p.importIdentifier(imp)
|
2019-07-30 12:00:02 -06:00
|
|
|
if ident == importPathToAssumedName(imp.ImportPath) {
|
2019-06-28 13:19:56 -06:00
|
|
|
return "" // ident not needed since the assumed and real names are the same.
|
|
|
|
}
|
|
|
|
return ident
|
|
|
|
}
|
|
|
|
|
|
|
|
// apply will perform the fixes on f in order.
|
2019-07-30 12:00:02 -06:00
|
|
|
func apply(fset *token.FileSet, f *ast.File, fixes []*ImportFix) {
|
2019-06-28 13:19:56 -06:00
|
|
|
for _, fix := range fixes {
|
2019-07-30 12:00:02 -06:00
|
|
|
switch fix.FixType {
|
|
|
|
case DeleteImport:
|
|
|
|
astutil.DeleteNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath)
|
|
|
|
case AddImport:
|
|
|
|
astutil.AddNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath)
|
|
|
|
case SetImportName:
|
2019-06-28 13:19:56 -06:00
|
|
|
// Find the matching import path and change the name.
|
|
|
|
for _, spec := range f.Imports {
|
2019-07-24 18:40:27 -06:00
|
|
|
path := strings.Trim(spec.Path.Value, `"`)
|
2019-07-30 12:00:02 -06:00
|
|
|
if path == fix.StmtInfo.ImportPath {
|
2019-06-28 13:19:56 -06:00
|
|
|
spec.Name = &ast.Ident{
|
2019-07-30 12:00:02 -06:00
|
|
|
Name: fix.StmtInfo.Name,
|
2019-06-28 13:19:56 -06:00
|
|
|
NamePos: spec.Pos(),
|
|
|
|
}
|
|
|
|
}
|
2018-11-20 13:24:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// assumeSiblingImportsValid assumes that siblings' use of packages is valid,
|
|
|
|
// adding the exports they use.
|
|
|
|
func (p *pass) assumeSiblingImportsValid() {
|
|
|
|
for _, f := range p.otherFiles {
|
|
|
|
refs := collectReferences(f)
|
|
|
|
imports := collectImports(f)
|
2019-07-30 12:00:02 -06:00
|
|
|
importsByName := map[string]*ImportInfo{}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
for _, imp := range imports {
|
|
|
|
importsByName[p.importIdentifier(imp)] = imp
|
|
|
|
}
|
|
|
|
for left, rights := range refs {
|
|
|
|
if imp, ok := importsByName[left]; ok {
|
2019-07-30 12:00:02 -06:00
|
|
|
if _, ok := stdlib[imp.ImportPath]; ok {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// We have the stdlib in memory; no need to guess.
|
2019-07-30 12:00:02 -06:00
|
|
|
rights = stdlib[imp.ImportPath]
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
p.addCandidate(imp, &packageInfo{
|
|
|
|
// no name; we already know it.
|
|
|
|
exports: rights,
|
|
|
|
})
|
|
|
|
}
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// addCandidate adds a candidate import to p, and merges in the information
|
|
|
|
// in pkg.
|
2019-07-30 12:00:02 -06:00
|
|
|
func (p *pass) addCandidate(imp *ImportInfo, pkg *packageInfo) {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
p.candidates = append(p.candidates, imp)
|
2019-07-30 12:00:02 -06:00
|
|
|
if existing, ok := p.knownPackages[imp.ImportPath]; ok {
|
2018-11-20 14:20:01 -07:00
|
|
|
if existing.name == "" {
|
|
|
|
existing.name = pkg.name
|
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
for export := range pkg.exports {
|
|
|
|
existing.exports[export] = true
|
|
|
|
}
|
|
|
|
} else {
|
2019-07-30 12:00:02 -06:00
|
|
|
p.knownPackages[imp.ImportPath] = pkg
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-10 13:09:03 -07:00
|
|
|
// fixImports adds and removes imports from f so that all its references are
|
|
|
|
// satisfied and there are no unused imports.
|
|
|
|
//
|
|
|
|
// This is declared as a variable rather than a function so goimports can
|
|
|
|
// easily be extended by adding a file with an init function.
|
|
|
|
var fixImports = fixImportsDefault
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) error {
|
2019-06-28 13:19:56 -06:00
|
|
|
fixes, err := getFixes(fset, f, filename, env)
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-06-28 13:19:56 -06:00
|
|
|
apply(fset, f, fixes)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-07-02 12:55:42 -06:00
|
|
|
// getFixes gets the import fixes that need to be made to f in order to fix the imports.
|
2019-06-28 13:19:56 -06:00
|
|
|
// It does not modify the ast.
|
2019-07-30 12:00:02 -06:00
|
|
|
func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) {
|
2019-06-28 13:19:56 -06:00
|
|
|
abs, err := filepath.Abs(filename)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
srcDir := filepath.Dir(abs)
|
2019-05-06 13:37:46 -06:00
|
|
|
if env.Debug {
|
2019-06-28 14:21:07 -06:00
|
|
|
env.Logf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir)
|
2017-05-12 14:54:58 -06:00
|
|
|
}
|
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
// First pass: looking only at f, and using the naive algorithm to
|
|
|
|
// derive package names from import paths, see if the file is already
|
|
|
|
// complete. We can't add any imports yet, because we don't know
|
|
|
|
// if missing references are actually package vars.
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
p := &pass{fset: fset, f: f, srcDir: srcDir}
|
2019-06-28 13:19:56 -06:00
|
|
|
if fixes, done := p.load(); done {
|
|
|
|
return fixes, nil
|
2017-05-12 14:54:58 -06:00
|
|
|
}
|
|
|
|
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
otherFiles := parseOtherFiles(fset, srcDir, filename)
|
|
|
|
|
|
|
|
// Second pass: add information from other files in the same package,
|
|
|
|
// like their package vars and imports.
|
|
|
|
p.otherFiles = otherFiles
|
2019-06-28 13:19:56 -06:00
|
|
|
if fixes, done := p.load(); done {
|
|
|
|
return fixes, nil
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now we can try adding imports from the stdlib.
|
|
|
|
p.assumeSiblingImportsValid()
|
2018-12-18 12:53:56 -07:00
|
|
|
addStdlibCandidates(p, p.missingRefs)
|
2019-06-28 13:19:56 -06:00
|
|
|
if fixes, done := p.fix(); done {
|
|
|
|
return fixes, nil
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Third pass: get real package names where we had previously used
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
// the naive algorithm. This is the first step that will use the
|
|
|
|
// environment, so we provide it here for the first time.
|
2019-05-06 13:37:46 -06:00
|
|
|
p = &pass{fset: fset, f: f, srcDir: srcDir, env: env}
|
2018-11-20 14:20:01 -07:00
|
|
|
p.loadRealPackageNames = true
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
p.otherFiles = otherFiles
|
2019-06-28 13:19:56 -06:00
|
|
|
if fixes, done := p.load(); done {
|
|
|
|
return fixes, nil
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
2018-12-18 12:53:56 -07:00
|
|
|
addStdlibCandidates(p, p.missingRefs)
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
p.assumeSiblingImportsValid()
|
2019-06-28 13:19:56 -06:00
|
|
|
if fixes, done := p.fix(); done {
|
|
|
|
return fixes, nil
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Go look for candidates in $GOPATH, etc. We don't necessarily load
|
|
|
|
// the real exports of sibling imports, so keep assuming their contents.
|
2018-12-18 12:53:56 -07:00
|
|
|
if err := addExternalCandidates(p, p.missingRefs, filename); err != nil {
|
2019-06-28 13:19:56 -06:00
|
|
|
return nil, err
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
p.lastTry = true
|
2019-06-28 13:19:56 -06:00
|
|
|
fixes, _ := p.fix()
|
|
|
|
return fixes, nil
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
2019-08-12 15:50:58 -06:00
|
|
|
// getAllCandidates gets all of the candidates to be imported, regardless of if they are needed.
|
|
|
|
func getAllCandidates(filename string, env *ProcessEnv) ([]ImportFix, error) {
|
|
|
|
// TODO(suzmue): scan for additional candidates and filter out
|
|
|
|
// current package.
|
|
|
|
|
|
|
|
// Get the stdlib candidates and sort by import path.
|
|
|
|
var paths []string
|
|
|
|
for importPath := range stdlib {
|
|
|
|
paths = append(paths, importPath)
|
|
|
|
}
|
|
|
|
sort.Strings(paths)
|
|
|
|
|
|
|
|
var imports []ImportFix
|
|
|
|
for _, importPath := range paths {
|
|
|
|
imports = append(imports, ImportFix{
|
|
|
|
StmtInfo: ImportInfo{
|
|
|
|
ImportPath: importPath,
|
|
|
|
},
|
|
|
|
IdentName: path.Base(importPath),
|
|
|
|
FixType: AddImport,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return imports, nil
|
|
|
|
}
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
// ProcessEnv contains environment variables and settings that affect the use of
|
2019-01-17 13:27:01 -07:00
|
|
|
// the go command, the go/build package, etc.
|
2019-05-06 13:37:46 -06:00
|
|
|
type ProcessEnv struct {
|
|
|
|
LocalPrefix string
|
|
|
|
Debug bool
|
|
|
|
|
2019-01-17 13:27:01 -07:00
|
|
|
// If non-empty, these will be used instead of the
|
|
|
|
// process-wide values.
|
2019-05-24 12:32:38 -06:00
|
|
|
GOPATH, GOROOT, GO111MODULE, GOPROXY, GOFLAGS, GOSUMDB string
|
|
|
|
WorkingDir string
|
2019-01-17 13:27:01 -07:00
|
|
|
|
|
|
|
// If true, use go/packages regardless of the environment.
|
|
|
|
ForceGoPackages bool
|
|
|
|
|
2019-06-28 14:21:07 -06:00
|
|
|
// Logf is the default logger for the ProcessEnv.
|
|
|
|
Logf func(format string, args ...interface{})
|
|
|
|
|
2019-07-03 13:23:05 -06:00
|
|
|
resolver Resolver
|
2019-01-17 13:27:01 -07:00
|
|
|
}
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
func (e *ProcessEnv) env() []string {
|
2019-01-17 13:27:01 -07:00
|
|
|
env := os.Environ()
|
|
|
|
add := func(k, v string) {
|
|
|
|
if v != "" {
|
|
|
|
env = append(env, k+"="+v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
add("GOPATH", e.GOPATH)
|
|
|
|
add("GOROOT", e.GOROOT)
|
|
|
|
add("GO111MODULE", e.GO111MODULE)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
add("GOPROXY", e.GOPROXY)
|
|
|
|
add("GOFLAGS", e.GOFLAGS)
|
2019-05-24 12:32:38 -06:00
|
|
|
add("GOSUMDB", e.GOSUMDB)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
if e.WorkingDir != "" {
|
|
|
|
add("PWD", e.WorkingDir)
|
|
|
|
}
|
2019-01-17 13:27:01 -07:00
|
|
|
return env
|
|
|
|
}
|
2018-11-20 14:20:01 -07:00
|
|
|
|
2019-07-03 13:23:05 -06:00
|
|
|
func (e *ProcessEnv) GetResolver() Resolver {
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
if e.resolver != nil {
|
|
|
|
return e.resolver
|
|
|
|
}
|
2019-01-17 13:27:01 -07:00
|
|
|
if e.ForceGoPackages {
|
2019-06-07 14:25:48 -06:00
|
|
|
e.resolver = &goPackagesResolver{env: e}
|
|
|
|
return e.resolver
|
2018-11-20 14:20:01 -07:00
|
|
|
}
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
out, err := e.invokeGo("env", "GOMOD")
|
|
|
|
if err != nil || len(bytes.TrimSpace(out.Bytes())) == 0 {
|
2019-06-07 14:25:48 -06:00
|
|
|
e.resolver = &gopathResolver{env: e}
|
|
|
|
return e.resolver
|
2018-11-20 14:20:01 -07:00
|
|
|
}
|
2019-07-03 13:23:05 -06:00
|
|
|
e.resolver = &ModuleResolver{env: e}
|
2019-06-07 14:25:48 -06:00
|
|
|
return e.resolver
|
2018-11-20 14:20:01 -07:00
|
|
|
}
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
func (e *ProcessEnv) newPackagesConfig(mode packages.LoadMode) *packages.Config {
|
2019-01-17 13:27:01 -07:00
|
|
|
return &packages.Config{
|
2018-11-20 14:20:01 -07:00
|
|
|
Mode: mode,
|
2019-01-17 13:27:01 -07:00
|
|
|
Dir: e.WorkingDir,
|
|
|
|
Env: e.env(),
|
2018-11-20 14:20:01 -07:00
|
|
|
}
|
2019-01-17 13:27:01 -07:00
|
|
|
}
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
func (e *ProcessEnv) buildContext() *build.Context {
|
2019-01-17 13:27:01 -07:00
|
|
|
ctx := build.Default
|
|
|
|
ctx.GOROOT = e.GOROOT
|
|
|
|
ctx.GOPATH = e.GOPATH
|
|
|
|
return &ctx
|
2018-11-20 14:20:01 -07:00
|
|
|
}
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
func (e *ProcessEnv) invokeGo(args ...string) (*bytes.Buffer, error) {
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
cmd := exec.Command("go", args...)
|
|
|
|
stdout := &bytes.Buffer{}
|
|
|
|
stderr := &bytes.Buffer{}
|
|
|
|
cmd.Stdout = stdout
|
|
|
|
cmd.Stderr = stderr
|
|
|
|
cmd.Env = e.env()
|
|
|
|
cmd.Dir = e.WorkingDir
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
if e.Debug {
|
2019-06-28 14:21:07 -06:00
|
|
|
defer func(start time.Time) { e.Logf("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now())
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
|
|
|
if err := cmd.Run(); err != nil {
|
|
|
|
return nil, fmt.Errorf("running go: %v (stderr:\n%s)", err, stderr)
|
|
|
|
}
|
|
|
|
return stdout, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func cmdDebugStr(cmd *exec.Cmd) string {
|
|
|
|
env := make(map[string]string)
|
|
|
|
for _, kv := range cmd.Env {
|
|
|
|
split := strings.Split(kv, "=")
|
|
|
|
k, v := split[0], split[1]
|
|
|
|
env[k] = v
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v GOPROXY=%v PWD=%v go %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["GOPROXY"], env["PWD"], cmd.Args)
|
|
|
|
}
|
|
|
|
|
|
|
|
func addStdlibCandidates(pass *pass, refs references) {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
add := func(pkg string) {
|
|
|
|
pass.addCandidate(
|
2019-07-30 12:00:02 -06:00
|
|
|
&ImportInfo{ImportPath: pkg},
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
&packageInfo{name: path.Base(pkg), exports: stdlib[pkg]})
|
|
|
|
}
|
|
|
|
for left := range refs {
|
|
|
|
if left == "rand" {
|
|
|
|
// Make sure we try crypto/rand before math/rand.
|
|
|
|
add("crypto/rand")
|
|
|
|
add("math/rand")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for importPath := range stdlib {
|
|
|
|
if path.Base(importPath) == left {
|
|
|
|
add(importPath)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-03 13:23:05 -06:00
|
|
|
// A Resolver does the build-system-specific parts of goimports.
|
|
|
|
type Resolver interface {
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
// loadPackageNames loads the package names in importPaths.
|
|
|
|
loadPackageNames(importPaths []string, srcDir string) (map[string]string, error)
|
|
|
|
// scan finds (at least) the packages satisfying refs. The returned slice is unordered.
|
|
|
|
scan(refs references) ([]*pkg, error)
|
2019-08-02 11:04:42 -06:00
|
|
|
// loadExports returns the set of exported symbols in the package at dir.
|
|
|
|
// It returns an error if the package name in dir does not match expectPackage.
|
|
|
|
// loadExports may be called concurrently.
|
|
|
|
loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
|
|
|
|
2019-07-03 13:23:05 -06:00
|
|
|
// gopackagesResolver implements resolver for GOPATH and module workspaces using go/packages.
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
type goPackagesResolver struct {
|
2019-05-06 13:37:46 -06:00
|
|
|
env *ProcessEnv
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *goPackagesResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
|
2019-07-30 17:43:22 -06:00
|
|
|
if len(importPaths) == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
cfg := r.env.newPackagesConfig(packages.LoadFiles)
|
|
|
|
pkgs, err := packages.Load(cfg, importPaths...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
names := map[string]string{}
|
|
|
|
for _, pkg := range pkgs {
|
|
|
|
names[VendorlessPath(pkg.PkgPath)] = pkg.Name
|
|
|
|
}
|
|
|
|
// We may not have found all the packages. Guess the rest.
|
|
|
|
for _, path := range importPaths {
|
|
|
|
if _, ok := names[path]; ok {
|
|
|
|
continue
|
|
|
|
}
|
2019-01-10 10:51:27 -07:00
|
|
|
names[path] = importPathToAssumedName(path)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
|
|
|
return names, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *goPackagesResolver) scan(refs references) ([]*pkg, error) {
|
2018-11-20 14:20:01 -07:00
|
|
|
var loadQueries []string
|
|
|
|
for pkgName := range refs {
|
2019-01-25 14:12:01 -07:00
|
|
|
loadQueries = append(loadQueries, "iamashamedtousethedisabledqueryname="+pkgName)
|
2018-11-20 14:20:01 -07:00
|
|
|
}
|
|
|
|
sort.Strings(loadQueries)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
cfg := r.env.newPackagesConfig(packages.LoadFiles)
|
2018-11-20 14:20:01 -07:00
|
|
|
goPackages, err := packages.Load(cfg, loadQueries...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var scan []*pkg
|
|
|
|
for _, goPackage := range goPackages {
|
|
|
|
scan = append(scan, &pkg{
|
|
|
|
dir: filepath.Dir(goPackage.CompiledGoFiles[0]),
|
|
|
|
importPathShort: VendorlessPath(goPackage.PkgPath),
|
|
|
|
goPackage: goPackage,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return scan, nil
|
|
|
|
}
|
|
|
|
|
2019-08-02 11:04:42 -06:00
|
|
|
func (r *goPackagesResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) {
|
|
|
|
if pkg.goPackage == nil {
|
|
|
|
return nil, fmt.Errorf("goPackage not set")
|
|
|
|
}
|
|
|
|
exports := map[string]bool{}
|
|
|
|
fset := token.NewFileSet()
|
|
|
|
for _, fname := range pkg.goPackage.CompiledGoFiles {
|
|
|
|
f, err := parser.ParseFile(fset, fname, nil, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("parsing %s: %v", fname, err)
|
|
|
|
}
|
|
|
|
for name := range f.Scope.Objects {
|
|
|
|
if ast.IsExported(name) {
|
|
|
|
exports[name] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return exports, nil
|
|
|
|
}
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
func addExternalCandidates(pass *pass, refs references, filename string) error {
|
2019-07-03 13:23:05 -06:00
|
|
|
dirScan, err := pass.env.GetResolver().scan(refs)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-11-20 14:20:01 -07:00
|
|
|
}
|
|
|
|
|
2013-12-17 19:21:03 -07:00
|
|
|
// Search for imports matching potential package references.
|
|
|
|
type result struct {
|
2019-07-30 12:00:02 -06:00
|
|
|
imp *ImportInfo
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
pkg *packageInfo
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
2018-04-24 14:05:29 -06:00
|
|
|
results := make(chan result, len(refs))
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.TODO())
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
defer func() {
|
|
|
|
cancel()
|
|
|
|
wg.Wait()
|
|
|
|
}()
|
|
|
|
var (
|
|
|
|
firstErr error
|
|
|
|
firstErrOnce sync.Once
|
|
|
|
)
|
2013-12-17 19:21:03 -07:00
|
|
|
for pkgName, symbols := range refs {
|
2018-04-24 14:05:29 -06:00
|
|
|
wg.Add(1)
|
2013-12-17 19:21:03 -07:00
|
|
|
go func(pkgName string, symbols map[string]bool) {
|
2018-04-24 14:05:29 -06:00
|
|
|
defer wg.Done()
|
|
|
|
|
2019-06-07 15:21:57 -06:00
|
|
|
found, err := findImport(ctx, pass, dirScan, pkgName, symbols, filename)
|
2018-04-24 14:05:29 -06:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
firstErrOnce.Do(func() {
|
|
|
|
firstErr = err
|
|
|
|
cancel()
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-11-20 14:20:01 -07:00
|
|
|
if found == nil {
|
2018-04-24 14:05:29 -06:00
|
|
|
return // No matching package.
|
|
|
|
}
|
|
|
|
|
2019-07-30 12:00:02 -06:00
|
|
|
imp := &ImportInfo{
|
|
|
|
ImportPath: found.importPathShort,
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pkg := &packageInfo{
|
|
|
|
name: pkgName,
|
|
|
|
exports: symbols,
|
|
|
|
}
|
|
|
|
results <- result{imp, pkg}
|
2013-12-17 19:21:03 -07:00
|
|
|
}(pkgName, symbols)
|
2018-04-24 14:05:29 -06:00
|
|
|
}
|
|
|
|
go func() {
|
|
|
|
wg.Wait()
|
|
|
|
close(results)
|
|
|
|
}()
|
|
|
|
|
|
|
|
for result := range results {
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
pass.addCandidate(result.imp, result.pkg)
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
return firstErr
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
|
2019-01-10 10:51:27 -07:00
|
|
|
// notIdentifier reports whether ch is an invalid identifier character.
|
|
|
|
func notIdentifier(ch rune) bool {
|
|
|
|
return !('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' ||
|
|
|
|
'0' <= ch && ch <= '9' ||
|
|
|
|
ch == '_' ||
|
|
|
|
ch >= utf8.RuneSelf && (unicode.IsLetter(ch) || unicode.IsDigit(ch)))
|
|
|
|
}
|
|
|
|
|
|
|
|
// importPathToAssumedName returns the assumed package name of an import path.
|
|
|
|
// It does this using only string parsing of the import path.
|
|
|
|
// It picks the last element of the path that does not look like a major
|
|
|
|
// version, and then picks the valid identifier off the start of that element.
|
|
|
|
// It is used to determine if a local rename should be added to an import for
|
|
|
|
// clarity.
|
|
|
|
// This function could be moved to a standard package and exported if we want
|
|
|
|
// for use in other tools.
|
|
|
|
func importPathToAssumedName(importPath string) string {
|
2018-11-07 15:40:17 -07:00
|
|
|
base := path.Base(importPath)
|
|
|
|
if strings.HasPrefix(base, "v") {
|
|
|
|
if _, err := strconv.Atoi(base[1:]); err == nil {
|
|
|
|
dir := path.Dir(importPath)
|
|
|
|
if dir != "." {
|
2019-01-10 10:51:27 -07:00
|
|
|
base = path.Base(dir)
|
2018-11-07 15:40:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-10 10:51:27 -07:00
|
|
|
base = strings.TrimPrefix(base, "go-")
|
|
|
|
if i := strings.IndexFunc(base, notIdentifier); i >= 0 {
|
|
|
|
base = base[:i]
|
|
|
|
}
|
2018-11-07 15:40:17 -07:00
|
|
|
return base
|
|
|
|
}
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
// gopathResolver implements resolver for GOPATH workspaces.
|
|
|
|
type gopathResolver struct {
|
2019-05-06 13:37:46 -06:00
|
|
|
env *ProcessEnv
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
|
|
|
|
names := map[string]string{}
|
|
|
|
for _, path := range importPaths {
|
|
|
|
names[path] = importPathToName(r.env, path, srcDir)
|
|
|
|
}
|
|
|
|
return names, nil
|
|
|
|
}
|
|
|
|
|
2019-07-02 12:55:42 -06:00
|
|
|
// importPathToName finds out the actual package name, as declared in its .go files.
|
2019-01-16 14:24:49 -07:00
|
|
|
// If there's a problem, it returns "".
|
2019-05-06 13:37:46 -06:00
|
|
|
func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName string) {
|
2018-11-07 15:40:17 -07:00
|
|
|
// Fast path for standard library without going to disk.
|
imports: redesign fixImports
Redesign fixImports to have a clearer workflow, and hopefully create
clear places to plug in go/packages. This change is mostly
performance/functionality neutral, but does clean up some corner cases.
The new flow centers around the pass type, which encapsulates the
process of loading information about the current code, adding possible
new imports, and trying to apply them. I'm hoping that it's easy to
understand what's happening just by reading fixImports, and that new
sources of information (e.g. a network service) fit well into that flow.
Where possible, I left the functions near where they were extracted in
hopes of making review easier, but it's probably not going to be easy.
Sorry. I might move them into a more reasonable order in a followup CL.
Notable modifications:
- The stdlib cache is restructured to match pass' internal storage.
- Sibling imports with conflicting names are considered.
- Package name lookups are batched, hopefully making it easier to plug
in go/packages.
Questions that might be worth answering:
- Should findImportGoPath really scan $GOROOT? Unless the user is working
on a development copy, it's totally redundant with the cache.
- What is the best way to combine candidates from multiple sources?
Right now the first one wins, and findStdlibCandidates relies on that
to get crypto/rand ahead of math/rand.
- In the third pass, should it assume sibling imports or should it
actually go load the exports? It didn't load them before, but that seems
arbitrary.
Change-Id: Ie4ad0b69bfbe9b16883f2b0517b1278575c9f540
Reviewed-on: https://go-review.googlesource.com/c/150339
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-11-19 15:56:05 -07:00
|
|
|
if _, ok := stdlib[importPath]; ok {
|
|
|
|
return path.Base(importPath) // stdlib packages always match their paths.
|
2018-11-07 15:40:17 -07:00
|
|
|
}
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
buildPkg, err := env.buildContext().Import(importPath, srcDir, build.FindOnly)
|
|
|
|
if err != nil {
|
|
|
|
return ""
|
2018-11-07 15:40:17 -07:00
|
|
|
}
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
pkgName, err := packageDirToName(buildPkg.Dir)
|
2019-01-16 14:24:49 -07:00
|
|
|
if err != nil {
|
|
|
|
return ""
|
2018-11-07 15:40:17 -07:00
|
|
|
}
|
2019-01-16 14:24:49 -07:00
|
|
|
return pkgName
|
2018-11-07 15:40:17 -07:00
|
|
|
}
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
// packageDirToName is a faster version of build.Import if
|
2019-07-02 12:55:42 -06:00
|
|
|
// the only thing desired is the package name. Given a directory,
|
|
|
|
// packageDirToName then only parses one file in the package,
|
2018-11-07 15:40:17 -07:00
|
|
|
// trusting that the files in the directory are consistent.
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
func packageDirToName(dir string) (packageName string, err error) {
|
|
|
|
d, err := os.Open(dir)
|
2018-11-07 15:40:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
names, err := d.Readdirnames(-1)
|
|
|
|
d.Close()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
sort.Strings(names) // to have predictable behavior
|
|
|
|
var lastErr error
|
|
|
|
var nfile int
|
|
|
|
for _, name := range names {
|
|
|
|
if !strings.HasSuffix(name, ".go") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if strings.HasSuffix(name, "_test.go") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
nfile++
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
fullFile := filepath.Join(dir, name)
|
2018-11-07 15:40:17 -07:00
|
|
|
|
|
|
|
fset := token.NewFileSet()
|
|
|
|
f, err := parser.ParseFile(fset, fullFile, nil, parser.PackageClauseOnly)
|
|
|
|
if err != nil {
|
|
|
|
lastErr = err
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
pkgName := f.Name.Name
|
|
|
|
if pkgName == "documentation" {
|
|
|
|
// Special case from go/build.ImportDir, not
|
|
|
|
// handled by ctx.MatchFile.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if pkgName == "main" {
|
|
|
|
// Also skip package main, assuming it's a +build ignore generator or example.
|
|
|
|
// Since you can't import a package main anyway, there's no harm here.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return pkgName, nil
|
|
|
|
}
|
|
|
|
if lastErr != nil {
|
|
|
|
return "", lastErr
|
|
|
|
}
|
|
|
|
return "", fmt.Errorf("no importable package found in %d Go files", nfile)
|
|
|
|
}
|
|
|
|
|
2013-12-17 19:21:03 -07:00
|
|
|
type pkg struct {
|
2018-11-20 14:20:01 -07:00
|
|
|
goPackage *packages.Package
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
dir string // absolute file path to pkg directory ("/usr/lib/go/src/net/http")
|
|
|
|
importPathShort string // vendorless import path ("net/http", "a/b")
|
2018-04-24 14:05:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type pkgDistance struct {
|
|
|
|
pkg *pkg
|
|
|
|
distance int // relative distance to target
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
|
2017-02-15 06:46:03 -07:00
|
|
|
// byDistanceOrImportPathShortLength sorts by relative distance breaking ties
|
|
|
|
// on the short import path length and then the import string itself.
|
2018-04-24 14:05:29 -06:00
|
|
|
type byDistanceOrImportPathShortLength []pkgDistance
|
2017-02-15 06:46:03 -07:00
|
|
|
|
|
|
|
func (s byDistanceOrImportPathShortLength) Len() int { return len(s) }
|
|
|
|
func (s byDistanceOrImportPathShortLength) Less(i, j int) bool {
|
|
|
|
di, dj := s[i].distance, s[j].distance
|
|
|
|
if di == -1 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if dj == -1 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if di != dj {
|
|
|
|
return di < dj
|
|
|
|
}
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
|
2018-04-24 14:05:29 -06:00
|
|
|
vi, vj := s[i].pkg.importPathShort, s[j].pkg.importPathShort
|
2017-02-15 06:46:03 -07:00
|
|
|
if len(vi) != len(vj) {
|
|
|
|
return len(vi) < len(vj)
|
|
|
|
}
|
|
|
|
return vi < vj
|
|
|
|
}
|
|
|
|
func (s byDistanceOrImportPathShortLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
2013-12-17 19:21:03 -07:00
|
|
|
|
2017-02-15 06:46:03 -07:00
|
|
|
func distance(basepath, targetpath string) int {
|
|
|
|
p, err := filepath.Rel(basepath, targetpath)
|
|
|
|
if err != nil {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
if p == "." {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return strings.Count(p, string(filepath.Separator)) + 1
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
func (r *gopathResolver) scan(_ references) ([]*pkg, error) {
|
2018-11-20 14:20:01 -07:00
|
|
|
dupCheck := make(map[string]bool)
|
|
|
|
var result []*pkg
|
|
|
|
|
2018-09-17 16:07:46 -06:00
|
|
|
var mu sync.Mutex
|
2016-07-17 18:47:35 -06:00
|
|
|
|
2018-09-27 16:21:00 -06:00
|
|
|
add := func(root gopathwalk.Root, dir string) {
|
2018-09-18 13:06:34 -06:00
|
|
|
mu.Lock()
|
|
|
|
defer mu.Unlock()
|
2018-09-17 16:07:46 -06:00
|
|
|
|
2018-11-20 14:20:01 -07:00
|
|
|
if _, dup := dupCheck[dir]; dup {
|
2018-09-18 13:06:34 -06:00
|
|
|
return
|
2018-09-17 16:07:46 -06:00
|
|
|
}
|
2018-11-20 14:20:01 -07:00
|
|
|
dupCheck[dir] = true
|
2018-09-27 16:21:00 -06:00
|
|
|
importpath := filepath.ToSlash(dir[len(root.Path)+len("/"):])
|
2018-11-20 14:20:01 -07:00
|
|
|
result = append(result, &pkg{
|
2018-09-17 16:07:46 -06:00
|
|
|
importPathShort: VendorlessPath(importpath),
|
|
|
|
dir: dir,
|
2018-11-20 14:20:01 -07:00
|
|
|
})
|
2014-04-08 17:43:52 -06:00
|
|
|
}
|
2019-05-06 13:37:46 -06:00
|
|
|
gopathwalk.Walk(gopathwalk.SrcDirsRoots(r.env.buildContext()), add, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: false})
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
return result, nil
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
2014-04-08 17:43:52 -06:00
|
|
|
|
2019-08-02 11:04:42 -06:00
|
|
|
func (r *gopathResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) {
|
|
|
|
return loadExportsFromFiles(ctx, r.env, expectPackage, pkg.dir)
|
|
|
|
}
|
|
|
|
|
2018-04-23 14:21:01 -06:00
|
|
|
// VendorlessPath returns the devendorized version of the import path ipath.
|
|
|
|
// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
|
2018-04-23 10:37:30 -06:00
|
|
|
func VendorlessPath(ipath string) string {
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
// Devendorize for use in import statement.
|
|
|
|
if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 {
|
|
|
|
return ipath[i+len("/vendor/"):]
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(ipath, "vendor/") {
|
|
|
|
return ipath[len("vendor/"):]
|
|
|
|
}
|
|
|
|
return ipath
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
|
2019-08-02 11:04:42 -06:00
|
|
|
func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, expectPackage string, dir string) (map[string]bool, error) {
|
2013-12-17 19:21:03 -07:00
|
|
|
exports := make(map[string]bool)
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
|
2019-01-03 11:53:54 -07:00
|
|
|
// Look for non-test, buildable .go files which could provide exports.
|
2019-08-02 11:04:42 -06:00
|
|
|
all, err := ioutil.ReadDir(dir)
|
2019-01-03 11:53:54 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var files []os.FileInfo
|
|
|
|
for _, fi := range all {
|
|
|
|
name := fi.Name()
|
|
|
|
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
|
|
|
|
continue
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
2019-08-02 11:04:42 -06:00
|
|
|
match, err := env.buildContext().MatchFile(dir, fi.Name())
|
2019-01-03 11:53:54 -07:00
|
|
|
if err != nil || !match {
|
|
|
|
continue
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
2019-01-03 11:53:54 -07:00
|
|
|
files = append(files, fi)
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
|
|
|
|
2019-01-03 11:53:54 -07:00
|
|
|
if len(files) == 0 {
|
2019-08-02 11:04:42 -06:00
|
|
|
return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", dir)
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
|
2013-12-18 10:09:37 -07:00
|
|
|
fset := token.NewFileSet()
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
for _, fi := range files {
|
2018-04-24 14:05:29 -06:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return nil, ctx.Err()
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2019-08-02 11:04:42 -06:00
|
|
|
fullFile := filepath.Join(dir, fi.Name())
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
f, err := parser.ParseFile(fset, fullFile, nil, 0)
|
|
|
|
if err != nil {
|
2019-01-03 11:53:54 -07:00
|
|
|
return nil, fmt.Errorf("parsing %s: %v", fullFile, err)
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
|
|
|
pkgName := f.Name.Name
|
|
|
|
if pkgName == "documentation" {
|
|
|
|
// Special case from go/build.ImportDir, not
|
2019-01-03 11:53:54 -07:00
|
|
|
// handled by MatchFile above.
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
if pkgName != expectPackage {
|
2019-08-02 11:04:42 -06:00
|
|
|
return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", dir, expectPackage, pkgName)
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
|
|
|
for name := range f.Scope.Objects {
|
|
|
|
if ast.IsExported(name) {
|
|
|
|
exports[name] = true
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
if env.Debug {
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
exportList := make([]string, 0, len(exports))
|
|
|
|
for k := range exports {
|
|
|
|
exportList = append(exportList, k)
|
|
|
|
}
|
|
|
|
sort.Strings(exportList)
|
2019-08-02 11:04:42 -06:00
|
|
|
env.Logf("loaded exports in dir %v (package %v): %v", dir, expectPackage, strings.Join(exportList, ", "))
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
2018-04-24 14:05:29 -06:00
|
|
|
return exports, nil
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// findImport searches for a package with the given symbols.
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
// If no package is found, findImport returns ("", false, nil)
|
2019-06-07 15:21:57 -06:00
|
|
|
func findImport(ctx context.Context, pass *pass, dirScan []*pkg, pkgName string, symbols map[string]bool, filename string) (*pkg, error) {
|
2017-02-15 06:46:03 -07:00
|
|
|
pkgDir, err := filepath.Abs(filename)
|
|
|
|
if err != nil {
|
2018-11-20 14:20:01 -07:00
|
|
|
return nil, err
|
2017-02-15 06:46:03 -07:00
|
|
|
}
|
|
|
|
pkgDir = filepath.Dir(pkgDir)
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
|
2016-07-17 18:47:35 -06:00
|
|
|
// Find candidate packages, looking only at their directory names first.
|
2018-04-24 14:05:29 -06:00
|
|
|
var candidates []pkgDistance
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
for _, pkg := range dirScan {
|
2019-06-07 15:21:57 -06:00
|
|
|
if pkg.dir == pkgDir && pass.f.Name.Name == pkgName {
|
|
|
|
// The candidate is in the same directory and has the
|
|
|
|
// same package name. Don't try to import ourselves.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if pkgIsCandidate(filename, pkgName, pkg) {
|
2018-04-24 14:05:29 -06:00
|
|
|
candidates = append(candidates, pkgDistance{
|
|
|
|
pkg: pkg,
|
|
|
|
distance: distance(pkgDir, pkg.dir),
|
|
|
|
})
|
2015-12-10 23:32:07 -07:00
|
|
|
}
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
2015-12-10 23:32:07 -07:00
|
|
|
|
2016-07-17 18:47:35 -06:00
|
|
|
// Sort the candidates by their import package length,
|
|
|
|
// assuming that shorter package names are better than long
|
|
|
|
// ones. Note that this sorts by the de-vendored name, so
|
|
|
|
// there's no "penalty" for vendoring.
|
2017-02-15 06:46:03 -07:00
|
|
|
sort.Sort(byDistanceOrImportPathShortLength(candidates))
|
2019-06-07 15:21:57 -06:00
|
|
|
if pass.env.Debug {
|
2018-04-24 14:05:29 -06:00
|
|
|
for i, c := range candidates {
|
2019-06-28 14:21:07 -06:00
|
|
|
pass.env.Logf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir)
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
|
|
|
}
|
2015-12-10 23:32:07 -07:00
|
|
|
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
// Collect exports for packages with matching names.
|
|
|
|
|
|
|
|
rescv := make([]chan *pkg, len(candidates))
|
|
|
|
for i := range candidates {
|
2018-04-24 14:05:29 -06:00
|
|
|
rescv[i] = make(chan *pkg, 1)
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
const maxConcurrentPackageImport = 4
|
|
|
|
loadExportsSem := make(chan struct{}, maxConcurrentPackageImport)
|
2013-12-17 19:21:03 -07:00
|
|
|
|
2018-04-24 14:05:29 -06:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
defer func() {
|
|
|
|
cancel()
|
|
|
|
wg.Wait()
|
|
|
|
}()
|
|
|
|
|
|
|
|
wg.Add(1)
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
go func() {
|
2018-04-24 14:05:29 -06:00
|
|
|
defer wg.Done()
|
|
|
|
for i, c := range candidates {
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
select {
|
|
|
|
case loadExportsSem <- struct{}{}:
|
2018-04-24 14:05:29 -06:00
|
|
|
case <-ctx.Done():
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
return
|
|
|
|
}
|
2018-04-24 14:05:29 -06:00
|
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
go func(c pkgDistance, resc chan<- *pkg) {
|
|
|
|
defer func() {
|
|
|
|
<-loadExportsSem
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
|
2019-08-02 11:04:42 -06:00
|
|
|
if pass.env.Debug {
|
|
|
|
pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName)
|
|
|
|
}
|
|
|
|
exports, err := pass.env.GetResolver().loadExports(ctx, pkgName, c.pkg)
|
2018-04-24 14:05:29 -06:00
|
|
|
if err != nil {
|
2019-06-07 15:21:57 -06:00
|
|
|
if pass.env.Debug {
|
2019-06-28 14:21:07 -06:00
|
|
|
pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
|
2019-01-03 11:53:54 -07:00
|
|
|
}
|
2018-04-24 14:05:29 -06:00
|
|
|
resc <- nil
|
|
|
|
return
|
2016-07-17 18:47:35 -06:00
|
|
|
}
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
|
|
|
|
// If it doesn't have the right
|
|
|
|
// symbols, send nil to mean no match.
|
|
|
|
for symbol := range symbols {
|
|
|
|
if !exports[symbol] {
|
2018-04-24 14:05:29 -06:00
|
|
|
resc <- nil
|
|
|
|
return
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
|
|
|
}
|
2018-04-24 14:05:29 -06:00
|
|
|
resc <- c.pkg
|
|
|
|
}(c, rescv[i])
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
|
|
|
}()
|
2018-04-24 14:05:29 -06:00
|
|
|
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
for _, resc := range rescv {
|
|
|
|
pkg := <-resc
|
|
|
|
if pkg == nil {
|
|
|
|
continue
|
|
|
|
}
|
2018-11-20 14:20:01 -07:00
|
|
|
return pkg, nil
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
}
|
2018-11-20 14:20:01 -07:00
|
|
|
return nil, nil
|
2015-12-10 23:32:07 -07:00
|
|
|
}
|
|
|
|
|
2016-07-18 15:58:52 -06:00
|
|
|
// pkgIsCandidate reports whether pkg is a candidate for satisfying the
|
|
|
|
// finding which package pkgIdent in the file named by filename is trying
|
|
|
|
// to refer to.
|
|
|
|
//
|
|
|
|
// This check is purely lexical and is meant to be as fast as possible
|
|
|
|
// because it's run over all $GOPATH directories to filter out poor
|
|
|
|
// candidates in order to limit the CPU and I/O later parsing the
|
|
|
|
// exports in candidate packages.
|
|
|
|
//
|
|
|
|
// filename is the file being formatted.
|
|
|
|
// pkgIdent is the package being searched for, like "client" (if
|
|
|
|
// searching for "client.New")
|
|
|
|
func pkgIsCandidate(filename, pkgIdent string, pkg *pkg) bool {
|
|
|
|
// Check "internal" and "vendor" visibility:
|
|
|
|
if !canUse(filename, pkg.dir) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Speed optimization to minimize disk I/O:
|
|
|
|
// the last two components on disk must contain the
|
|
|
|
// package name somewhere.
|
|
|
|
//
|
|
|
|
// This permits mismatch naming like directory
|
|
|
|
// "go-foo" being package "foo", or "pkg.v3" being "pkg",
|
|
|
|
// or directory "google.golang.org/api/cloudbilling/v1"
|
|
|
|
// being package "cloudbilling", but doesn't
|
|
|
|
// permit a directory "foo" to be package
|
|
|
|
// "bar", which is strongly discouraged
|
|
|
|
// anyway. There's no reason goimports needs
|
2018-08-10 12:13:41 -06:00
|
|
|
// to be slow just to accommodate that.
|
2016-07-18 15:58:52 -06:00
|
|
|
lastTwo := lastTwoComponents(pkg.importPathShort)
|
|
|
|
if strings.Contains(lastTwo, pkgIdent) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(pkgIdent) {
|
|
|
|
lastTwo = lowerASCIIAndRemoveHyphen(lastTwo)
|
|
|
|
if strings.Contains(lastTwo, pkgIdent) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func hasHyphenOrUpperASCII(s string) bool {
|
|
|
|
for i := 0; i < len(s); i++ {
|
|
|
|
b := s[i]
|
|
|
|
if b == '-' || ('A' <= b && b <= 'Z') {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func lowerASCIIAndRemoveHyphen(s string) (ret string) {
|
|
|
|
buf := make([]byte, 0, len(s))
|
|
|
|
for i := 0; i < len(s); i++ {
|
|
|
|
b := s[i]
|
|
|
|
switch {
|
|
|
|
case b == '-':
|
|
|
|
continue
|
|
|
|
case 'A' <= b && b <= 'Z':
|
|
|
|
buf = append(buf, b+('a'-'A'))
|
|
|
|
default:
|
|
|
|
buf = append(buf, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return string(buf)
|
|
|
|
}
|
|
|
|
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
// canUse reports whether the package in dir is usable from filename,
|
|
|
|
// respecting the Go "internal" and "vendor" visibility rules.
|
2015-12-10 23:32:07 -07:00
|
|
|
func canUse(filename, dir string) bool {
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
// Fast path check, before any allocations. If it doesn't contain vendor
|
|
|
|
// or internal, it's not tricky:
|
|
|
|
// Note that this can false-negative on directories like "notinternal",
|
|
|
|
// but we check it correctly below. This is just a fast path.
|
|
|
|
if !strings.Contains(dir, "vendor") && !strings.Contains(dir, "internal") {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2015-12-10 23:32:07 -07:00
|
|
|
dirSlash := filepath.ToSlash(dir)
|
|
|
|
if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
// Vendor or internal directory only visible from children of parent.
|
|
|
|
// That means the path from the current directory to the target directory
|
|
|
|
// can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal
|
|
|
|
// or bar/vendor or bar/internal.
|
|
|
|
// After stripping all the leading ../, the only okay place to see vendor or internal
|
|
|
|
// is at the very beginning of the path.
|
2016-07-21 00:51:57 -06:00
|
|
|
absfile, err := filepath.Abs(filename)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
absdir, err := filepath.Abs(dir)
|
2015-12-10 23:32:07 -07:00
|
|
|
if err != nil {
|
|
|
|
return false
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
2016-07-21 00:51:57 -06:00
|
|
|
rel, err := filepath.Rel(absfile, absdir)
|
2015-12-10 23:32:07 -07:00
|
|
|
if err != nil {
|
|
|
|
return false
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
2015-12-10 23:32:07 -07:00
|
|
|
relSlash := filepath.ToSlash(rel)
|
|
|
|
if i := strings.LastIndex(relSlash, "../"); i >= 0 {
|
|
|
|
relSlash = relSlash[i+len("../"):]
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
2015-12-10 23:32:07 -07:00
|
|
|
return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal")
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
|
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
|
|
|
// lastTwoComponents returns at most the last two path components
|
|
|
|
// of v, using either / or \ as the path separator.
|
|
|
|
func lastTwoComponents(v string) string {
|
|
|
|
nslash := 0
|
|
|
|
for i := len(v) - 1; i >= 0; i-- {
|
|
|
|
if v[i] == '/' || v[i] == '\\' {
|
|
|
|
nslash++
|
|
|
|
if nslash == 2 {
|
|
|
|
return v[i:]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2013-12-17 19:21:03 -07:00
|
|
|
type visitFn func(node ast.Node) ast.Visitor
|
|
|
|
|
|
|
|
func (fn visitFn) Visit(node ast.Node) ast.Visitor {
|
|
|
|
return fn(node)
|
|
|
|
}
|