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 (
|
2019-12-26 17:13:58 -07:00
|
|
|
"context"
|
2019-05-06 13:37:46 -06:00
|
|
|
"flag"
|
2018-08-10 13:20:38 -06:00
|
|
|
"fmt"
|
2019-09-12 14:41:22 -06:00
|
|
|
"go/build"
|
2019-10-09 17:05:30 -06:00
|
|
|
"log"
|
2018-11-07 15:40:17 -07:00
|
|
|
"path/filepath"
|
2019-10-04 13:38:18 -06:00
|
|
|
"reflect"
|
2015-12-10 23:32:07 -07:00
|
|
|
"runtime"
|
2019-12-27 13:46:49 -07:00
|
|
|
"sort"
|
2016-07-17 18:47:35 -06:00
|
|
|
"strings"
|
2019-10-13 15:23:09 -06:00
|
|
|
"sync"
|
2013-12-17 19:21:03 -07:00
|
|
|
"testing"
|
2018-10-22 15:56:19 -06:00
|
|
|
|
|
|
|
"golang.org/x/tools/go/packages/packagestest"
|
2013-12-17 19:21:03 -07:00
|
|
|
)
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
var testDebug = flag.Bool("debug", false, "enable debug output")
|
|
|
|
|
2013-12-17 19:21:03 -07:00
|
|
|
var tests = []struct {
|
2016-04-05 10:10:15 -06:00
|
|
|
name string
|
|
|
|
formatOnly bool
|
|
|
|
in, out string
|
2013-12-17 19:21:03 -07:00
|
|
|
}{
|
|
|
|
// Adding an import to an existing parenthesized import
|
|
|
|
{
|
|
|
|
name: "factored_imports_add",
|
|
|
|
in: `package foo
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
func bar() {
|
|
|
|
var b bytes.Buffer
|
|
|
|
fmt.Println(b.String())
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
var b bytes.Buffer
|
|
|
|
fmt.Println(b.String())
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adding an import to an existing parenthesized import,
|
|
|
|
// verifying it goes into the first section.
|
|
|
|
{
|
|
|
|
name: "factored_imports_add_first_sec",
|
|
|
|
in: `package foo
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
2013-12-17 19:21:03 -07:00
|
|
|
)
|
|
|
|
func bar() {
|
|
|
|
var b bytes.Buffer
|
2018-10-26 12:54:05 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
2013-12-17 19:21:03 -07:00
|
|
|
fmt.Println(b.String())
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
2013-12-17 19:21:03 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
var b bytes.Buffer
|
2018-10-26 12:54:05 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
2013-12-17 19:21:03 -07:00
|
|
|
fmt.Println(b.String())
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adding an import to an existing parenthesized import,
|
|
|
|
// verifying it goes into the first section. (test 2)
|
|
|
|
{
|
|
|
|
name: "factored_imports_add_first_sec_2",
|
|
|
|
in: `package foo
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
2013-12-17 19:21:03 -07:00
|
|
|
)
|
|
|
|
func bar() {
|
|
|
|
_ = math.NaN
|
|
|
|
_ = fmt.Sprintf
|
2018-10-26 12:54:05 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
2013-12-17 19:21:03 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
_ = math.NaN
|
|
|
|
_ = fmt.Sprintf
|
2018-10-26 12:54:05 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adding a new import line, without parens
|
|
|
|
{
|
|
|
|
name: "add_import_section",
|
|
|
|
in: `package foo
|
|
|
|
func bar() {
|
|
|
|
var b bytes.Buffer
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import "bytes"
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
var b bytes.Buffer
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Adding two new imports, which should make a parenthesized import decl.
|
|
|
|
{
|
|
|
|
name: "add_import_paren_section",
|
|
|
|
in: `package foo
|
|
|
|
func bar() {
|
|
|
|
_, _ := bytes.Buffer, zip.NewReader
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"archive/zip"
|
|
|
|
"bytes"
|
|
|
|
)
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
_, _ := bytes.Buffer, zip.NewReader
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Make sure we don't add things twice
|
|
|
|
{
|
|
|
|
name: "no_double_add",
|
|
|
|
in: `package foo
|
|
|
|
func bar() {
|
|
|
|
_, _ := bytes.Buffer, bytes.NewReader
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import "bytes"
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
_, _ := bytes.Buffer, bytes.NewReader
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
// Make sure we don't add packages that don't have the right exports
|
|
|
|
{
|
|
|
|
name: "no_mismatched_add",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
_ := bytes.NonexistentSymbol
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
_ := bytes.NonexistentSymbol
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
2013-12-17 19:21:03 -07:00
|
|
|
// Remove unused imports, 1 of a factored block
|
|
|
|
{
|
|
|
|
name: "remove_unused_1_of_2",
|
|
|
|
in: `package foo
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
_, _ := bytes.Buffer, bytes.NewReader
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
2017-02-09 02:39:36 -07:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
)
|
2013-12-17 19:21:03 -07:00
|
|
|
|
|
|
|
func bar() {
|
|
|
|
_, _ := bytes.Buffer, bytes.NewReader
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Remove unused imports, 2 of 2
|
|
|
|
{
|
|
|
|
name: "remove_unused_2_of_2",
|
|
|
|
in: `package foo
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Remove unused imports, 1 of 1
|
|
|
|
{
|
|
|
|
name: "remove_unused_1_of_1",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Don't remove empty imports.
|
|
|
|
{
|
|
|
|
name: "dont_remove_empty_imports",
|
|
|
|
in: `package foo
|
|
|
|
import (
|
|
|
|
_ "image/png"
|
|
|
|
_ "image/jpeg"
|
|
|
|
)
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "image/jpeg"
|
|
|
|
_ "image/png"
|
|
|
|
)
|
|
|
|
`,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
|
2013-12-17 19:21:03 -07:00
|
|
|
// Don't remove dot imports.
|
|
|
|
{
|
|
|
|
name: "dont_remove_dot_imports",
|
|
|
|
in: `package foo
|
|
|
|
import (
|
|
|
|
. "foo"
|
|
|
|
. "bar"
|
|
|
|
)
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
. "bar"
|
|
|
|
. "foo"
|
|
|
|
)
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Skip refs the parser can resolve.
|
|
|
|
{
|
|
|
|
name: "skip_resolved_refs",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
func f() {
|
|
|
|
type t struct{ Println func(string) }
|
|
|
|
fmt := t{Println: func(string) {}}
|
|
|
|
fmt.Println("foo")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
func f() {
|
|
|
|
type t struct{ Println func(string) }
|
|
|
|
fmt := t{Println: func(string) {}}
|
|
|
|
fmt.Println("foo")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Do not add a package we already have a resolution for.
|
|
|
|
{
|
|
|
|
name: "skip_template",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
import "html/template"
|
|
|
|
|
|
|
|
func f() { t = template.New("sometemplate") }
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import "html/template"
|
|
|
|
|
|
|
|
func f() { t = template.New("sometemplate") }
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Don't touch cgo
|
|
|
|
{
|
|
|
|
name: "cgo",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
/*
|
|
|
|
#include <foo.h>
|
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
/*
|
|
|
|
#include <foo.h>
|
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Put some things in their own section
|
|
|
|
{
|
|
|
|
name: "make_sections",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
)
|
|
|
|
|
|
|
|
func foo () {
|
|
|
|
_, _ = os.Args, fmt.Println
|
2018-10-26 12:54:05 -06:00
|
|
|
_, _ = snappy.ErrCorrupt, p.P
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
|
|
|
"rsc.io/p"
|
2013-12-17 19:21:03 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func foo() {
|
|
|
|
_, _ = os.Args, fmt.Println
|
2018-10-26 12:54:05 -06:00
|
|
|
_, _ = snappy.ErrCorrupt, p.P
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
2019-08-12 12:56:31 -06:00
|
|
|
// Merge import blocks, even when no additions are required.
|
|
|
|
{
|
|
|
|
name: "merge_import_blocks_no_fix",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
import "os"
|
2013-12-17 19:21:03 -07:00
|
|
|
|
2019-08-12 12:56:31 -06:00
|
|
|
import (
|
|
|
|
"rsc.io/p"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _, _ = os.Args, fmt.Println
|
|
|
|
var _, _ = snappy.ErrCorrupt, p.P
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/golang/snappy"
|
|
|
|
"rsc.io/p"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _, _ = os.Args, fmt.Println
|
|
|
|
var _, _ = snappy.ErrCorrupt, p.P
|
|
|
|
`,
|
|
|
|
},
|
2013-12-17 19:21:03 -07:00
|
|
|
// Delete existing empty import block
|
|
|
|
{
|
|
|
|
name: "delete_empty_import_block",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
import ()
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Use existing empty import block
|
|
|
|
{
|
|
|
|
name: "use_empty_import_block",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
import ()
|
|
|
|
|
|
|
|
func f() {
|
|
|
|
_ = fmt.Println
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
func f() {
|
|
|
|
_ = fmt.Println
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Blank line before adding new section.
|
|
|
|
{
|
|
|
|
name: "blank_line_before_new_group",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
)
|
|
|
|
|
|
|
|
func f() {
|
|
|
|
_ = net.Dial
|
|
|
|
_ = fmt.Printf
|
2018-10-09 15:32:55 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
2013-12-17 19:21:03 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func f() {
|
|
|
|
_ = net.Dial
|
|
|
|
_ = fmt.Printf
|
2018-10-09 15:32:55 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Blank line between standard library and third-party stuff.
|
|
|
|
{
|
|
|
|
name: "blank_line_separating_std_and_third_party",
|
|
|
|
in: `package foo
|
|
|
|
|
|
|
|
import (
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
2013-12-17 19:21:03 -07:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
)
|
|
|
|
|
|
|
|
func f() {
|
|
|
|
_ = net.Dial
|
|
|
|
_ = fmt.Printf
|
|
|
|
_ = snappy.Foo
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
2013-12-17 19:21:03 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func f() {
|
|
|
|
_ = net.Dial
|
|
|
|
_ = fmt.Printf
|
|
|
|
_ = snappy.Foo
|
|
|
|
}
|
2013-12-18 10:09:37 -07:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// golang.org/issue/6884
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "new_imports_before_comment",
|
2013-12-18 10:09:37 -07:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
// A comment
|
|
|
|
func main() {
|
|
|
|
fmt.Println("Hello, world")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
// A comment
|
|
|
|
func main() {
|
|
|
|
fmt.Println("Hello, world")
|
|
|
|
}
|
2014-02-07 18:03:34 -07:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// golang.org/issue/7132
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "new_section_for_dotless_import",
|
2014-02-07 18:03:34 -07:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"gu"
|
2018-10-26 12:54:05 -06:00
|
|
|
"manypackages.com/packagea"
|
2014-02-07 18:03:34 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2018-10-26 12:54:05 -06:00
|
|
|
a = packagea.A
|
|
|
|
b = gu.A
|
2014-02-07 18:03:34 -07:00
|
|
|
c = fmt.Printf
|
|
|
|
)
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2018-10-24 09:31:02 -06:00
|
|
|
|
2014-02-07 18:03:34 -07:00
|
|
|
"gu"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"manypackages.com/packagea"
|
2014-02-07 18:03:34 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2018-10-26 12:54:05 -06:00
|
|
|
a = packagea.A
|
|
|
|
b = gu.A
|
2014-02-07 18:03:34 -07:00
|
|
|
c = fmt.Printf
|
|
|
|
)
|
2014-03-25 07:37:10 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "fragment_with_main",
|
2014-04-28 15:15:33 -06:00
|
|
|
in: `func main(){fmt.Println("Hello, world")}`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
func main() { fmt.Println("Hello, world") }
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "fragment_without_main",
|
2014-04-28 15:15:33 -06:00
|
|
|
in: `func notmain(){fmt.Println("Hello, world")}`,
|
|
|
|
out: `import "fmt"
|
|
|
|
|
|
|
|
func notmain() { fmt.Println("Hello, world") }`,
|
|
|
|
},
|
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding,
and other imports before that.
Currently, DeleteImport assumes there's a blank line-sized hole left behind
where the import was, and always deletes it. That blank line-sized hole is there in all cases
except the above edge case.
This fix checks for that edge case, and does not remove the blank line-sized hole.
The CL also adds a previously failing test case that catches this scenario. After the change to
DeleteImport, the new test passes (along with all other tests).
Fixes golang/go#7679.
Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly
matching to what you would get if you printed the AST and parsed it back. This is how the
rest of the package and the current tests work (i.e., they only check that printing the AST gives
the correct output).
Changing that is very hard, if not impossible, at least not
without resorting to manipulating AST via printing, text manipulation and parsing.
This is okay for most usages, but it does create potential problems. For example,
astutil.Imports() currently only works correctly on freshly parsed AST. If that AST
is manipulated via astutil funcs, then Imports() may not always generate correct
output. However, thas is a separate issue and should be treated as such.
LGTM=bradfitz
R=golang-codereviews, gobot, adonovan, bradfitz
CC=golang-codereviews
https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
|
|
|
|
|
|
|
// Remove first import within in a 2nd/3rd/4th/etc. section.
|
|
|
|
// golang.org/issue/7679
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "remove_first_import_in_section",
|
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding,
and other imports before that.
Currently, DeleteImport assumes there's a blank line-sized hole left behind
where the import was, and always deletes it. That blank line-sized hole is there in all cases
except the above edge case.
This fix checks for that edge case, and does not remove the blank line-sized hole.
The CL also adds a previously failing test case that catches this scenario. After the change to
DeleteImport, the new test passes (along with all other tests).
Fixes golang/go#7679.
Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly
matching to what you would get if you printed the AST and parsed it back. This is how the
rest of the package and the current tests work (i.e., they only check that printing the AST gives
the correct output).
Changing that is very hard, if not impossible, at least not
without resorting to manipulating AST via printing, text manipulation and parsing.
This is okay for most usages, but it does create potential problems. For example,
astutil.Imports() currently only works correctly on freshly parsed AST. If that AST
is manipulated via astutil funcs, then Imports() may not always generate correct
output. However, thas is a separate issue and should be treated as such.
LGTM=bradfitz
R=golang-codereviews, gobot, adonovan, bradfitz
CC=golang-codereviews
https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"manypackages.com/packagea"
|
|
|
|
"manypackages.com/packageb"
|
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding,
and other imports before that.
Currently, DeleteImport assumes there's a blank line-sized hole left behind
where the import was, and always deletes it. That blank line-sized hole is there in all cases
except the above edge case.
This fix checks for that edge case, and does not remove the blank line-sized hole.
The CL also adds a previously failing test case that catches this scenario. After the change to
DeleteImport, the new test passes (along with all other tests).
Fixes golang/go#7679.
Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly
matching to what you would get if you printed the AST and parsed it back. This is how the
rest of the package and the current tests work (i.e., they only check that printing the AST gives
the correct output).
Changing that is very hard, if not impossible, at least not
without resorting to manipulating AST via printing, text manipulation and parsing.
This is okay for most usages, but it does create potential problems. For example,
astutil.Imports() currently only works correctly on freshly parsed AST. If that AST
is manipulated via astutil funcs, then Imports() may not always generate correct
output. However, thas is a separate issue and should be treated as such.
LGTM=bradfitz
R=golang-codereviews, gobot, adonovan, bradfitz
CC=golang-codereviews
https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
var _ = fmt.Println
|
2018-10-26 12:54:05 -06:00
|
|
|
//var _ = packagea.A
|
|
|
|
var _ = packageb.B
|
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding,
and other imports before that.
Currently, DeleteImport assumes there's a blank line-sized hole left behind
where the import was, and always deletes it. That blank line-sized hole is there in all cases
except the above edge case.
This fix checks for that edge case, and does not remove the blank line-sized hole.
The CL also adds a previously failing test case that catches this scenario. After the change to
DeleteImport, the new test passes (along with all other tests).
Fixes golang/go#7679.
Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly
matching to what you would get if you printed the AST and parsed it back. This is how the
rest of the package and the current tests work (i.e., they only check that printing the AST gives
the correct output).
Changing that is very hard, if not impossible, at least not
without resorting to manipulating AST via printing, text manipulation and parsing.
This is okay for most usages, but it does create potential problems. For example,
astutil.Imports() currently only works correctly on freshly parsed AST. If that AST
is manipulated via astutil funcs, then Imports() may not always generate correct
output. However, thas is a separate issue and should be treated as such.
LGTM=bradfitz
R=golang-codereviews, gobot, adonovan, bradfitz
CC=golang-codereviews
https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"manypackages.com/packageb"
|
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding,
and other imports before that.
Currently, DeleteImport assumes there's a blank line-sized hole left behind
where the import was, and always deletes it. That blank line-sized hole is there in all cases
except the above edge case.
This fix checks for that edge case, and does not remove the blank line-sized hole.
The CL also adds a previously failing test case that catches this scenario. After the change to
DeleteImport, the new test passes (along with all other tests).
Fixes golang/go#7679.
Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly
matching to what you would get if you printed the AST and parsed it back. This is how the
rest of the package and the current tests work (i.e., they only check that printing the AST gives
the correct output).
Changing that is very hard, if not impossible, at least not
without resorting to manipulating AST via printing, text manipulation and parsing.
This is okay for most usages, but it does create potential problems. For example,
astutil.Imports() currently only works correctly on freshly parsed AST. If that AST
is manipulated via astutil funcs, then Imports() may not always generate correct
output. However, thas is a separate issue and should be treated as such.
LGTM=bradfitz
R=golang-codereviews, gobot, adonovan, bradfitz
CC=golang-codereviews
https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
var _ = fmt.Println
|
2018-10-26 12:54:05 -06:00
|
|
|
//var _ = packagea.A
|
|
|
|
var _ = packageb.B
|
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding,
and other imports before that.
Currently, DeleteImport assumes there's a blank line-sized hole left behind
where the import was, and always deletes it. That blank line-sized hole is there in all cases
except the above edge case.
This fix checks for that edge case, and does not remove the blank line-sized hole.
The CL also adds a previously failing test case that catches this scenario. After the change to
DeleteImport, the new test passes (along with all other tests).
Fixes golang/go#7679.
Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly
matching to what you would get if you printed the AST and parsed it back. This is how the
rest of the package and the current tests work (i.e., they only check that printing the AST gives
the correct output).
Changing that is very hard, if not impossible, at least not
without resorting to manipulating AST via printing, text manipulation and parsing.
This is okay for most usages, but it does create potential problems. For example,
astutil.Imports() currently only works correctly on freshly parsed AST. If that AST
is manipulated via astutil funcs, then Imports() may not always generate correct
output. However, thas is a separate issue and should be treated as such.
LGTM=bradfitz
R=golang-codereviews, gobot, adonovan, bradfitz
CC=golang-codereviews
https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
|
|
|
}
|
2014-05-20 15:02:16 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Blank line can be added before all types of import declarations.
|
|
|
|
// golang.org/issue/7866
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "new_section_for_all_kinds_of_imports",
|
2014-05-20 15:02:16 -06:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2018-10-26 12:54:05 -06:00
|
|
|
renamed_packagea "manypackages.com/packagea"
|
2014-05-20 15:02:16 -06:00
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
. "manypackages.com/packageb"
|
2014-05-20 15:02:16 -06:00
|
|
|
"io"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
_ "manypackages.com/packagec"
|
2014-05-20 15:02:16 -06:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
|
2014-05-20 15:02:16 -06:00
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
renamed_packagea "manypackages.com/packagea"
|
2018-10-24 09:31:02 -06:00
|
|
|
|
|
|
|
"io"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
. "manypackages.com/packageb"
|
2018-10-24 09:31:02 -06:00
|
|
|
|
|
|
|
"strings"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
_ "manypackages.com/packagec"
|
2014-05-20 15:02:16 -06:00
|
|
|
)
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
|
2014-07-28 18:15:17 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Non-idempotent comment formatting
|
|
|
|
// golang.org/issue/8035
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "comments_formatted",
|
2014-07-28 18:15:17 -06:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt" // A
|
|
|
|
"go/ast" // B
|
2018-10-26 12:54:05 -06:00
|
|
|
_ "manypackages.com/packagec" // C
|
2014-07-28 18:15:17 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() { _, _ = fmt.Print, ast.Walk }
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt" // A
|
|
|
|
"go/ast" // B
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
_ "manypackages.com/packagec" // C
|
2014-07-28 18:15:17 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() { _, _ = fmt.Print, ast.Walk }
|
2014-08-14 12:51:51 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Failure to delete all duplicate imports
|
|
|
|
// golang.org/issue/8459
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "remove_duplicates",
|
2014-08-14 12:51:51 -06:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"log"
|
|
|
|
"math"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() { fmt.Println("pi:", math.Pi) }
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() { fmt.Println("pi:", math.Pi) }
|
2015-03-25 12:52:44 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Too aggressive prefix matching
|
|
|
|
// golang.org/issue/9961
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "no_extra_groups",
|
2015-03-25 12:52:44 -06:00
|
|
|
in: `package p
|
|
|
|
|
|
|
|
import (
|
|
|
|
"zip"
|
|
|
|
|
|
|
|
"rsc.io/p"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ = fmt.Print
|
|
|
|
_ = zip.Store
|
|
|
|
_ p.P
|
|
|
|
_ = regexp.Compile
|
|
|
|
)
|
|
|
|
`,
|
|
|
|
out: `package p
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
"zip"
|
|
|
|
|
|
|
|
"rsc.io/p"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ = fmt.Print
|
|
|
|
_ = zip.Store
|
|
|
|
_ p.P
|
|
|
|
_ = regexp.Compile
|
|
|
|
)
|
2015-08-07 09:16:12 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Unused named import is mistaken for unnamed import
|
|
|
|
// golang.org/issue/8149
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "named_import_doesnt_provide_package_name",
|
2015-08-07 09:16:12 -06:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import foo "fmt"
|
|
|
|
|
|
|
|
func main() { fmt.Println() }
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import "fmt"
|
2016-02-25 12:09:00 -07:00
|
|
|
|
|
|
|
func main() { fmt.Println() }
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Unused named import is mistaken for unnamed import
|
|
|
|
// golang.org/issue/8149
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "unused_named_import_removed",
|
2016-02-25 12:09:00 -07:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
x "fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() { fmt.Println() }
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
2017-02-09 02:39:36 -07:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
2015-08-07 09:16:12 -06:00
|
|
|
|
|
|
|
func main() { fmt.Println() }
|
2016-04-05 10:10:15 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
2019-01-03 11:53:54 -07:00
|
|
|
{
|
|
|
|
name: "ignore_unexported_identifier",
|
|
|
|
in: `package main
|
|
|
|
var _ = fmt.unexported`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
var _ = fmt.unexported
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
2016-04-05 10:10:15 -06:00
|
|
|
// FormatOnly
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "formatonly_works",
|
2016-04-05 10:10:15 -06:00
|
|
|
formatOnly: true,
|
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2018-10-26 12:54:05 -06:00
|
|
|
"manypackages.com/packagea"
|
2016-04-05 10:10:15 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {}
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"manypackages.com/packagea"
|
2016-04-05 10:10:15 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {}
|
2017-02-09 02:39:36 -07:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "preserve_import_group",
|
2017-02-09 02:39:36 -07:00
|
|
|
in: `package p
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _ = fmt.Sprintf
|
|
|
|
`,
|
|
|
|
out: `package p
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _ = fmt.Sprintf
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "import_grouping_not_path_dependent_no_groups",
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2018-10-09 15:32:55 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
_ = p.P
|
|
|
|
_ = time.Parse
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
"rsc.io/p"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2018-10-09 15:32:55 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
_ = p.P
|
|
|
|
_ = time.Parse
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "import_grouping_not_path_dependent_existing_group",
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2018-10-09 15:32:55 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
_ = p.P
|
|
|
|
_ = time.Parse
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"github.com/golang/snappy"
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
"rsc.io/p"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2018-10-09 15:32:55 -06:00
|
|
|
_ = snappy.ErrCorrupt
|
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
|
|
|
_ = p.P
|
|
|
|
_ = time.Parse
|
|
|
|
}
|
2018-02-10 04:48:53 -07:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
// golang.org/issue/12097
|
2018-02-10 04:48:53 -07:00
|
|
|
{
|
2018-10-26 12:54:05 -06:00
|
|
|
name: "package_statement_insertion_preserves_comments",
|
2018-02-10 04:48:53 -07:00
|
|
|
in: `// a
|
|
|
|
// b
|
|
|
|
// c
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
_ = fmt.Println
|
|
|
|
}`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
// a
|
|
|
|
// b
|
|
|
|
// c
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
_ = fmt.Println
|
|
|
|
}
|
2018-07-01 09:28:45 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "import_comment_stays_on_import",
|
2018-07-01 09:28:45 -06:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math" // fun
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
x := math.MaxInt64
|
|
|
|
fmt.Println(strings.Join(",", []string{"hi"}), x)
|
|
|
|
}`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math" // fun
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
x := math.MaxInt64
|
|
|
|
fmt.Println(strings.Join(",", []string{"hi"}), x)
|
|
|
|
}
|
2018-07-08 20:40:43 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "no_blank_after_comment",
|
2018-07-08 20:40:43 -06:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "io"
|
|
|
|
_ "net/http"
|
|
|
|
_ "net/http/pprof" // install the pprof http handlers
|
|
|
|
_ "strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "io"
|
|
|
|
_ "net/http"
|
|
|
|
_ "net/http/pprof" // install the pprof http handlers
|
|
|
|
_ "strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "no_blank_after_comment_reordered",
|
2018-07-08 20:40:43 -06:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "io"
|
|
|
|
_ "net/http/pprof" // install the pprof http handlers
|
|
|
|
_ "net/http"
|
|
|
|
_ "strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "io"
|
|
|
|
_ "net/http"
|
|
|
|
_ "net/http/pprof" // install the pprof http handlers
|
|
|
|
_ "strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "no_blank_after_comment_unnamed",
|
2018-07-08 20:40:43 -06:00
|
|
|
in: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
_ "net/http/pprof" // install the pprof http handlers
|
|
|
|
"strings"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"manypackages.com/packagea"
|
2018-07-08 20:40:43 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
_ = strings.ToUpper("hello")
|
|
|
|
_ = io.EOF
|
|
|
|
var (
|
|
|
|
_ json.Number
|
|
|
|
_ *http.Request
|
2018-10-26 12:54:05 -06:00
|
|
|
_ packagea.A
|
2018-07-08 20:40:43 -06:00
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
_ "net/http/pprof" // install the pprof http handlers
|
|
|
|
"strings"
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
"manypackages.com/packagea"
|
2018-07-08 20:40:43 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
_ = strings.ToUpper("hello")
|
|
|
|
_ = io.EOF
|
|
|
|
var (
|
|
|
|
_ json.Number
|
|
|
|
_ *http.Request
|
2018-10-26 12:54:05 -06:00
|
|
|
_ packagea.A
|
2018-07-08 20:40:43 -06:00
|
|
|
)
|
|
|
|
}
|
2018-07-09 13:50:39 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "blank_after_package_statement_with_comment",
|
2018-07-09 13:50:39 -06:00
|
|
|
in: `package p // comment
|
|
|
|
|
|
|
|
import "math"
|
|
|
|
|
|
|
|
var _ = fmt.Printf
|
|
|
|
`,
|
|
|
|
out: `package p // comment
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
var _ = fmt.Printf
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "blank_after_package_statement_no_comment",
|
2018-07-09 13:50:39 -06:00
|
|
|
in: `package p
|
|
|
|
|
|
|
|
import "math"
|
|
|
|
|
|
|
|
var _ = fmt.Printf
|
|
|
|
`,
|
|
|
|
out: `package p
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
var _ = fmt.Printf
|
2018-06-06 14:43:48 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "cryptorand_preferred_easy_possible",
|
|
|
|
in: `package p
|
|
|
|
|
|
|
|
var _ = rand.Read
|
|
|
|
`,
|
|
|
|
out: `package p
|
|
|
|
|
|
|
|
import "crypto/rand"
|
|
|
|
|
|
|
|
var _ = rand.Read
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
name: "cryptorand_preferred_easy_impossible",
|
|
|
|
in: `package p
|
|
|
|
|
|
|
|
var _ = rand.NewZipf
|
|
|
|
`,
|
|
|
|
out: `package p
|
|
|
|
|
|
|
|
import "math/rand"
|
|
|
|
|
|
|
|
var _ = rand.NewZipf
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
name: "cryptorand_preferred_complex_possible",
|
|
|
|
in: `package p
|
|
|
|
|
|
|
|
var _, _ = rand.Read, rand.Prime
|
|
|
|
`,
|
|
|
|
out: `package p
|
|
|
|
|
|
|
|
import "crypto/rand"
|
|
|
|
|
|
|
|
var _, _ = rand.Read, rand.Prime
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
name: "cryptorand_preferred_complex_impossible",
|
|
|
|
in: `package p
|
|
|
|
|
|
|
|
var _, _ = rand.Read, rand.NewZipf
|
|
|
|
`,
|
|
|
|
out: `package p
|
|
|
|
|
|
|
|
import "math/rand"
|
|
|
|
|
|
|
|
var _, _ = rand.Read, rand.NewZipf
|
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding,
and other imports before that.
Currently, DeleteImport assumes there's a blank line-sized hole left behind
where the import was, and always deletes it. That blank line-sized hole is there in all cases
except the above edge case.
This fix checks for that edge case, and does not remove the blank line-sized hole.
The CL also adds a previously failing test case that catches this scenario. After the change to
DeleteImport, the new test passes (along with all other tests).
Fixes golang/go#7679.
Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly
matching to what you would get if you printed the AST and parsed it back. This is how the
rest of the package and the current tests work (i.e., they only check that printing the AST gives
the correct output).
Changing that is very hard, if not impossible, at least not
without resorting to manipulating AST via printing, text manipulation and parsing.
This is okay for most usages, but it does create potential problems. For example,
astutil.Imports() currently only works correctly on freshly parsed AST. If that AST
is manipulated via astutil funcs, then Imports() may not always generate correct
output. However, thas is a separate issue and should be treated as such.
LGTM=bradfitz
R=golang-codereviews, gobot, adonovan, bradfitz
CC=golang-codereviews
https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
|
|
|
`,
|
|
|
|
},
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
func TestSimpleCases(t *testing.T) {
|
2019-05-06 13:37:46 -06:00
|
|
|
const localPrefix = "local.com,github.com/local"
|
2018-10-10 17:17:04 -06:00
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
options := &Options{
|
|
|
|
TabWidth: 8,
|
|
|
|
TabIndent: true,
|
|
|
|
Comments: true,
|
|
|
|
Fragment: true,
|
|
|
|
FormatOnly: tt.formatOnly,
|
|
|
|
}
|
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
2018-10-26 12:54:05 -06:00
|
|
|
Name: "golang.org/fake",
|
|
|
|
Files: fm{"x.go": tt.in},
|
2018-10-22 15:56:19 -06:00
|
|
|
},
|
2018-10-26 12:54:05 -06:00
|
|
|
// Skeleton non-stdlib packages for use during testing.
|
|
|
|
// Each includes one arbitrary symbol, e.g. the first declaration in the first file.
|
|
|
|
// Try not to add more without a good reason.
|
|
|
|
// DO NOT USE PACKAGES NOT LISTED HERE -- they will be downloaded!
|
2018-10-22 15:56:19 -06:00
|
|
|
{
|
|
|
|
Name: "rsc.io",
|
|
|
|
Files: fm{"p/x.go": "package p\nfunc P(){}\n"},
|
|
|
|
},
|
|
|
|
{
|
2018-10-26 12:54:05 -06:00
|
|
|
Name: "github.com/golang/snappy",
|
|
|
|
Files: fm{"x.go": "package snappy\nvar ErrCorrupt error\n"},
|
2018-10-22 15:56:19 -06:00
|
|
|
},
|
|
|
|
{
|
2018-10-26 12:54:05 -06:00
|
|
|
Name: "manypackages.com",
|
|
|
|
Files: fm{
|
|
|
|
"packagea/x.go": "package packagea\nfunc A(){}\n",
|
|
|
|
"packageb/x.go": "package packageb\nfunc B(){}\n",
|
|
|
|
"packagec/x.go": "package packagec\nfunc C(){}\n",
|
|
|
|
"packaged/x.go": "package packaged\nfunc D(){}\n",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "local.com",
|
|
|
|
Files: fm{"foo/x.go": "package foo\nfunc Foo(){}\n"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "github.com/local",
|
|
|
|
Files: fm{"bar/x.go": "package bar\nfunc Bar(){}\n"},
|
2018-10-22 15:56:19 -06:00
|
|
|
},
|
2018-10-10 17:17:04 -06:00
|
|
|
},
|
2019-05-06 13:37:46 -06:00
|
|
|
}.test(t, func(t *goimportTest) {
|
|
|
|
t.env.LocalPrefix = localPrefix
|
|
|
|
t.assertProcessEquals("golang.org/fake", "x.go", nil, options, tt.out)
|
|
|
|
})
|
|
|
|
|
2018-10-10 17:17:04 -06:00
|
|
|
})
|
|
|
|
}
|
2017-03-23 23:58:37 -06:00
|
|
|
}
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
func TestAppengine(t *testing.T) {
|
|
|
|
const input = `package p
|
|
|
|
|
|
|
|
var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
|
|
|
|
`
|
|
|
|
|
|
|
|
const want = `package p
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"appengine"
|
|
|
|
"appengine/datastore"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
|
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
|
|
|
gopathOnly: true, // can't create a module named appengine, so no module tests.
|
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "golang.org/fake",
|
|
|
|
Files: fm{"x.go": input},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "appengine",
|
|
|
|
Files: fm{
|
|
|
|
"x.go": "package appengine\nfunc Main(){}\n",
|
|
|
|
"datastore/x.go": "package datastore\nvar ErrInvalidEntityType error\n",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.processTest(t, "golang.org/fake", "x.go", nil, nil, want)
|
|
|
|
}
|
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
func TestReadFromFilesystem(t *testing.T) {
|
2017-03-23 23:58:37 -06:00
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
in, out string
|
|
|
|
}{
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "works",
|
2017-03-23 23:58:37 -06:00
|
|
|
in: `package foo
|
|
|
|
func bar() {
|
|
|
|
fmt.Println("hi")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `package foo
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
fmt.Println("hi")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
{
|
2018-10-09 15:32:55 -06:00
|
|
|
name: "missing_package",
|
2017-03-23 23:58:37 -06:00
|
|
|
in: `
|
|
|
|
func bar() {
|
|
|
|
fmt.Println("hi")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
out: `
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
func bar() {
|
|
|
|
fmt.Println("hi")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
2018-10-09 15:32:55 -06:00
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
options := &Options{
|
|
|
|
TabWidth: 8,
|
|
|
|
TabIndent: true,
|
|
|
|
Comments: true,
|
|
|
|
Fragment: true,
|
|
|
|
}
|
2018-10-09 15:32:55 -06:00
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "golang.org/fake",
|
|
|
|
Files: fm{"x.go": tt.in},
|
2018-10-09 15:32:55 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "golang.org/fake", "x.go", nil, options, tt.out)
|
2018-10-09 15:32:55 -06:00
|
|
|
})
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
2018-10-09 15:32:55 -06:00
|
|
|
|
2013-12-17 19:21:03 -07:00
|
|
|
}
|
|
|
|
|
2016-06-07 14:47:49 -06:00
|
|
|
// Test support for packages in GOPATH that are actually symlinks.
|
|
|
|
// Also test that a symlink loop does not block the process.
|
|
|
|
func TestImportSymlinks(t *testing.T) {
|
2016-07-17 10:24:21 -06:00
|
|
|
switch runtime.GOOS {
|
|
|
|
case "windows", "plan9":
|
2016-07-21 00:51:57 -06:00
|
|
|
t.Skipf("skipping test on %q as there are no symlinks", runtime.GOOS)
|
2016-06-07 14:47:49 -06:00
|
|
|
}
|
|
|
|
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package p
|
2016-06-07 14:47:49 -06:00
|
|
|
|
|
|
|
var (
|
|
|
|
_ = fmt.Print
|
|
|
|
_ = mypkg.Foo
|
|
|
|
)
|
|
|
|
`
|
2018-10-10 17:17:04 -06:00
|
|
|
const want = `package p
|
2016-06-07 14:47:49 -06:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2018-10-22 15:56:19 -06:00
|
|
|
|
|
|
|
"golang.org/fake/x/y/mypkg"
|
2016-06-07 14:47:49 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ = fmt.Print
|
|
|
|
_ = mypkg.Foo
|
|
|
|
)
|
|
|
|
`
|
2018-10-10 17:17:04 -06:00
|
|
|
|
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "golang.org/fake",
|
|
|
|
Files: fm{
|
|
|
|
"target/f.go": "package mypkg\nvar Foo = 123\n",
|
|
|
|
"x/y/mypkg": packagestest.Symlink("../../target"), // valid symlink
|
|
|
|
"x/y/apkg": packagestest.Symlink(".."), // symlink loop
|
|
|
|
"myotherpackage/toformat.go": input,
|
|
|
|
},
|
2018-10-10 17:17:04 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "golang.org/fake", "myotherpackage/toformat.go", nil, nil, want)
|
2018-10-09 15:32:55 -06:00
|
|
|
}
|
2016-11-15 09:48:37 -07:00
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
func TestImportSymlinksWithIgnore(t *testing.T) {
|
|
|
|
switch runtime.GOOS {
|
|
|
|
case "windows", "plan9":
|
|
|
|
t.Skipf("skipping test on %q as there are no symlinks", runtime.GOOS)
|
2016-11-15 09:48:37 -07:00
|
|
|
}
|
|
|
|
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package p
|
2016-11-15 09:48:37 -07:00
|
|
|
|
|
|
|
var (
|
|
|
|
_ = fmt.Print
|
|
|
|
_ = mypkg.Foo
|
|
|
|
)
|
|
|
|
`
|
2018-10-10 17:17:04 -06:00
|
|
|
const want = `package p
|
2016-11-15 09:48:37 -07:00
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ = fmt.Print
|
|
|
|
_ = mypkg.Foo
|
|
|
|
)
|
|
|
|
`
|
2018-10-10 17:17:04 -06:00
|
|
|
|
|
|
|
testConfig{
|
2018-10-26 12:54:05 -06:00
|
|
|
gopathOnly: true,
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "golang.org/fake",
|
|
|
|
Files: fm{
|
|
|
|
"target/f.go": "package mypkg\nvar Foo = 123\n",
|
|
|
|
"x/y/mypkg": packagestest.Symlink("../../target"), // valid symlink
|
|
|
|
"x/y/apkg": packagestest.Symlink(".."), // symlink loop
|
|
|
|
"myotherpkg/toformat.go": input,
|
|
|
|
"../../.goimportsignore": "golang.org/fake/x/y/mypkg\n",
|
|
|
|
},
|
2018-10-10 17:17:04 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "golang.org/fake", "myotherpkg/toformat.go", nil, nil, want)
|
2016-06-07 14:47:49 -06:00
|
|
|
}
|
|
|
|
|
2018-07-09 10:01:45 -06:00
|
|
|
// Test for x/y/v2 convention for package y.
|
2018-10-09 15:32:55 -06:00
|
|
|
func TestModuleVersion(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package p
|
2018-07-09 10:01:45 -06:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2018-06-06 14:43:48 -06:00
|
|
|
"github.com/foo/v2"
|
2018-07-09 10:01:45 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ = fmt.Print
|
|
|
|
_ = foo.Foo
|
|
|
|
)
|
|
|
|
`
|
2018-10-10 17:17:04 -06:00
|
|
|
|
|
|
|
testConfig{
|
2018-11-20 13:24:09 -07:00
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "mypkg.com/outpkg",
|
|
|
|
Files: fm{"toformat.go": input},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "github.com/foo/v2",
|
|
|
|
Files: fm{"x.go": "package foo\n func Foo(){}\n"},
|
|
|
|
},
|
2018-10-10 17:17:04 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, input)
|
2018-07-09 10:01:45 -06:00
|
|
|
}
|
|
|
|
|
2016-04-13 15:57:13 -06:00
|
|
|
// Test for correctly identifying the name of a vendored package when it
|
|
|
|
// differs from its directory name. In this test, the import line
|
2019-01-10 10:51:27 -07:00
|
|
|
// "mypkg.com/mypkg_v1" would be removed if goimports wasn't able to detect
|
2016-04-13 15:57:13 -06:00
|
|
|
// that the package name is "mypkg".
|
2018-10-09 15:32:55 -06:00
|
|
|
func TestVendorPackage(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package p
|
2018-10-29 15:38:22 -06:00
|
|
|
import (
|
|
|
|
"fmt"
|
2019-01-10 10:51:27 -07:00
|
|
|
"mypkg.com/mypkg_v1"
|
2016-04-13 15:57:13 -06:00
|
|
|
)
|
2018-11-20 13:24:09 -07:00
|
|
|
var _, _ = fmt.Print, mypkg.Foo
|
|
|
|
`
|
2018-10-29 15:38:22 -06:00
|
|
|
|
2018-11-20 13:24:09 -07:00
|
|
|
const want = `package p
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2019-01-10 10:51:27 -07:00
|
|
|
mypkg "mypkg.com/mypkg_v1"
|
2018-11-07 15:40:17 -07:00
|
|
|
)
|
2018-11-20 13:24:09 -07:00
|
|
|
|
|
|
|
var _, _ = fmt.Print, mypkg.Foo
|
2016-04-13 15:57:13 -06:00
|
|
|
`
|
2018-11-20 13:24:09 -07:00
|
|
|
|
2018-10-10 17:17:04 -06:00
|
|
|
testConfig{
|
2018-10-26 12:54:05 -06:00
|
|
|
gopathOnly: true,
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "mypkg.com/outpkg",
|
|
|
|
Files: fm{
|
2019-01-10 10:51:27 -07:00
|
|
|
"vendor/mypkg.com/mypkg_v1/f.go": "package mypkg\nvar Foo = 123\n",
|
2018-10-22 15:56:19 -06:00
|
|
|
"toformat.go": input,
|
|
|
|
},
|
2018-10-10 17:17:04 -06:00
|
|
|
},
|
2018-11-20 13:24:09 -07:00
|
|
|
}.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, want)
|
imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package
containing "rand.Read" was "crypto/rand".
goimports was updated to know that, and zstdlib.go contains a note
that it's ambiguous:
"rand.Perm": "math/rand",
"rand.Prime": "crypto/rand",
"rand.Rand": "math/rand",
// "rand.Read" is ambiguous
"rand.Reader": "crypto/rand",
"rand.Seed": "math/rand",
"rand.Source": "math/rand",
The intention originally was that such ambiguous things would
never be resolved, even randomly.
But a later change added support for build.Default.SrcDirs, which
meant GOROOT was also searched for ambiguous things. Or maybe I forget
the history.
In any case, when goimports tried to resolve "rand.Read", the
findImportStdlib check was returning nothing, which lead to the
$GOROOT being searched, where math/rand was picked by chance. That's a
dangerous default when the intentional might've been crypto/rand.
Special case it and prefer crypto/rand if there's no more specific
clue either way.
Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c
Reviewed-on: https://go-review.googlesource.com/24847
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
2016-07-11 16:38:22 -06:00
|
|
|
}
|
2015-12-10 23:32:07 -07:00
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
func TestInternal(t *testing.T) {
|
|
|
|
const input = `package bar
|
2015-12-10 23:32:07 -07:00
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
var _ = race.Acquire
|
|
|
|
`
|
|
|
|
const importAdded = `package bar
|
|
|
|
|
2018-10-22 15:56:19 -06:00
|
|
|
import "foo.com/internal/race"
|
2015-12-10 23:32:07 -07:00
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
var _ = race.Acquire
|
|
|
|
`
|
|
|
|
|
2018-10-10 17:17:04 -06:00
|
|
|
// Packages under the same directory should be able to use internal packages.
|
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"internal/race/x.go": "package race\n func Acquire(){}\n",
|
|
|
|
"bar/x.go": input,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "foo.com", "bar/x.go", nil, nil, importAdded)
|
2018-10-10 17:17:04 -06:00
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
// Packages outside the same directory should not.
|
2018-10-10 17:17:04 -06:00
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{"internal/race/x.go": "package race\n func Acquire(){}\n"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "bar.com",
|
|
|
|
Files: fm{"x.go": input},
|
|
|
|
},
|
2018-10-10 17:17:04 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "bar.com", "x.go", nil, nil, input)
|
2015-12-10 23:32:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestProcessVendor(t *testing.T) {
|
2018-10-09 15:32:55 -06:00
|
|
|
const input = `package p
|
2015-12-10 23:32:07 -07:00
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
var _ = hpack.HuffmanDecode
|
|
|
|
`
|
|
|
|
const want = `package p
|
2015-12-10 23:32:07 -07:00
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
import "golang.org/x/net/http2/hpack"
|
|
|
|
|
|
|
|
var _ = hpack.HuffmanDecode
|
|
|
|
`
|
|
|
|
testConfig{
|
2018-11-20 14:20:01 -07:00
|
|
|
gopathOnly: true,
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"vendor/golang.org/x/net/http2/hpack/huffman.go": "package hpack\nfunc HuffmanDecode() { }\n",
|
|
|
|
"bar/x.go": input,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "foo.com", "bar/x.go", nil, nil, want)
|
2015-12-10 23:32:07 -07:00
|
|
|
}
|
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
func TestFindStdlib(t *testing.T) {
|
2014-01-26 10:47:31 -07:00
|
|
|
tests := []struct {
|
|
|
|
pkg string
|
|
|
|
symbols []string
|
|
|
|
want string
|
|
|
|
}{
|
|
|
|
{"http", []string{"Get"}, "net/http"},
|
|
|
|
{"http", []string{"Get", "Post"}, "net/http"},
|
|
|
|
{"http", []string{"Get", "Foo"}, ""},
|
|
|
|
{"bytes", []string{"Buffer"}, "bytes"},
|
|
|
|
{"ioutil", []string{"Discard"}, "io/ioutil"},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
2018-10-09 15:32:55 -06:00
|
|
|
input := "package p\n"
|
|
|
|
for _, sym := range tt.symbols {
|
|
|
|
input += fmt.Sprintf("var _ = %s.%s\n", tt.pkg, sym)
|
2014-01-26 10:47:31 -07:00
|
|
|
}
|
2019-05-06 13:37:46 -06:00
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{"x.go": input},
|
|
|
|
},
|
|
|
|
}.test(t, func(t *goimportTest) {
|
|
|
|
buf, err := t.process("foo.com", "x.go", nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if got := string(buf); !strings.Contains(got, tt.want) {
|
|
|
|
t.Errorf("Process(%q) = %q, wanted it to contain %q", input, buf, tt.want)
|
|
|
|
}
|
|
|
|
})
|
2014-01-26 10:47:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-12 14:41:22 -06:00
|
|
|
// https://golang.org/issue/31814
|
|
|
|
func TestStdlibNotPrefixed(t *testing.T) {
|
|
|
|
const input = `package p
|
|
|
|
var _ = bytes.Buffer
|
|
|
|
`
|
|
|
|
const want = `package p
|
|
|
|
|
|
|
|
import "bytes"
|
|
|
|
|
|
|
|
var _ = bytes.Buffer
|
|
|
|
`
|
|
|
|
// Force a scan of the stdlib.
|
|
|
|
savedStdlib := stdlib
|
|
|
|
defer func() { stdlib = savedStdlib }()
|
2019-11-04 12:02:48 -07:00
|
|
|
stdlib = map[string][]string{}
|
2019-09-12 14:41:22 -06:00
|
|
|
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "ignored.com",
|
|
|
|
},
|
|
|
|
}.test(t, func(t *goimportTest) {
|
|
|
|
// Run in GOROOT/src so that the std module shows up in go list -m all.
|
|
|
|
t.env.WorkingDir = filepath.Join(t.env.GOROOT, "src")
|
|
|
|
got, err := t.processNonModule(filepath.Join(t.env.GOROOT, "src/x.go"), []byte(input), nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Process() = %v", err)
|
|
|
|
}
|
|
|
|
if string(got) != want {
|
|
|
|
t.Errorf("Got:\n%s\nWant:\n%s", got, want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
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
|
|
|
type testConfig struct {
|
2019-12-23 17:04:25 -07:00
|
|
|
gopathOnly bool
|
|
|
|
module packagestest.Module
|
|
|
|
modules []packagestest.Module
|
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-10-22 15:56:19 -06:00
|
|
|
// fm is the type for a packagestest.Module's Files, abbreviated for shorter lines.
|
|
|
|
type fm map[string]interface{}
|
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
|
|
|
|
|
|
|
func (c testConfig) test(t *testing.T, fn func(*goimportTest)) {
|
2018-10-10 17:17:04 -06:00
|
|
|
t.Helper()
|
|
|
|
|
2018-10-22 15:56:19 -06:00
|
|
|
if c.module.Name != "" {
|
|
|
|
c.modules = []packagestest.Module{c.module}
|
2016-07-25 09:05:58 -06:00
|
|
|
}
|
|
|
|
|
2018-11-20 14:20:01 -07:00
|
|
|
for _, exporter := range packagestest.All {
|
2019-12-23 17:04:25 -07:00
|
|
|
t.Run(exporter.Name(), func(t *testing.T) {
|
2018-10-26 12:54:05 -06:00
|
|
|
t.Helper()
|
2019-12-23 17:04:25 -07:00
|
|
|
if c.gopathOnly && exporter.Name() == "Modules" {
|
2019-05-06 13:37:46 -06:00
|
|
|
t.Skip("test marked GOPATH-only")
|
|
|
|
}
|
2018-11-20 14:20:01 -07:00
|
|
|
exported := packagestest.Export(t, exporter, c.modules)
|
2018-10-26 12:54:05 -06:00
|
|
|
defer exported.Cleanup()
|
|
|
|
|
|
|
|
env := make(map[string]string)
|
|
|
|
for _, kv := range exported.Config.Env {
|
|
|
|
split := strings.Split(kv, "=")
|
|
|
|
k, v := split[0], split[1]
|
|
|
|
env[k] = v
|
|
|
|
}
|
2018-10-22 15:56:19 -06:00
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
it := &goimportTest{
|
2019-01-17 13:27:01 -07:00
|
|
|
T: t,
|
2019-05-06 13:37:46 -06:00
|
|
|
env: &ProcessEnv{
|
2019-12-23 17:04:25 -07:00
|
|
|
GOROOT: env["GOROOT"],
|
|
|
|
GOPATH: env["GOPATH"],
|
|
|
|
GO111MODULE: env["GO111MODULE"],
|
|
|
|
GOSUMDB: env["GOSUMDB"],
|
|
|
|
WorkingDir: exported.Config.Dir,
|
|
|
|
Debug: *testDebug,
|
|
|
|
Logf: log.Printf,
|
2019-01-17 13:27:01 -07:00
|
|
|
},
|
2018-10-26 12:54:05 -06:00
|
|
|
exported: exported,
|
|
|
|
}
|
2019-09-12 14:41:22 -06:00
|
|
|
if it.env.GOROOT == "" {
|
|
|
|
// packagestest clears out GOROOT to work around https://golang.org/issue/32849,
|
|
|
|
// which isn't relevant here. Fill it back in so we can find the standard library.
|
|
|
|
it.env.GOROOT = build.Default.GOROOT
|
|
|
|
}
|
2018-10-26 12:54:05 -06:00
|
|
|
fn(it)
|
|
|
|
})
|
2018-10-10 17:17:04 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-22 15:56:19 -06:00
|
|
|
func (c testConfig) processTest(t *testing.T, module, file string, contents []byte, opts *Options, want string) {
|
2018-10-10 17:17:04 -06:00
|
|
|
t.Helper()
|
|
|
|
c.test(t, func(t *goimportTest) {
|
|
|
|
t.Helper()
|
2019-05-06 13:37:46 -06:00
|
|
|
t.assertProcessEquals(module, file, contents, opts, want)
|
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
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
type goimportTest struct {
|
|
|
|
*testing.T
|
2019-05-06 13:37:46 -06:00
|
|
|
env *ProcessEnv
|
2018-10-22 15:56:19 -06:00
|
|
|
exported *packagestest.Exported
|
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
|
|
|
func (t *goimportTest) process(module, file string, contents []byte, opts *Options) ([]byte, error) {
|
2018-10-10 17:17:04 -06:00
|
|
|
t.Helper()
|
2018-10-26 12:54:05 -06:00
|
|
|
f := t.exported.File(module, file)
|
|
|
|
if f == "" {
|
|
|
|
t.Fatalf("%v not found in exported files (typo in filename?)", file)
|
2018-10-22 15:56:19 -06:00
|
|
|
}
|
2019-05-06 13:37:46 -06:00
|
|
|
return t.processNonModule(f, contents, opts)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *goimportTest) processNonModule(file string, contents []byte, opts *Options) ([]byte, error) {
|
|
|
|
if opts == nil {
|
|
|
|
opts = &Options{Comments: true, TabIndent: true, TabWidth: 8}
|
|
|
|
}
|
2019-10-13 15:23:09 -06:00
|
|
|
// ProcessEnv is not safe for concurrent use. Make a copy.
|
|
|
|
env := *t.env
|
|
|
|
opts.Env = &env
|
2019-05-06 13:37:46 -06:00
|
|
|
return Process(file, contents, opts)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *goimportTest) assertProcessEquals(module, file string, contents []byte, opts *Options, want string) {
|
|
|
|
buf, err := t.process(module, file, contents, opts)
|
2018-10-10 17:17:04 -06:00
|
|
|
if err != nil {
|
2018-10-22 15:56:19 -06:00
|
|
|
t.Fatalf("Process() = %v", err)
|
2018-10-10 17:17:04 -06:00
|
|
|
}
|
|
|
|
if string(buf) != want {
|
|
|
|
t.Errorf("Got:\n%s\nWant:\n%s", buf, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
// Tests that added imports are renamed when the import path's base doesn't
|
2018-11-20 13:24:09 -07:00
|
|
|
// match its package 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
|
|
|
func TestRenameWhenPackageNameMismatch(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package main
|
|
|
|
const Y = bar.X`
|
|
|
|
|
|
|
|
const want = `package main
|
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 13:24:09 -07:00
|
|
|
import bar "foo.com/foo/bar/baz"
|
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 Y = bar.X
|
|
|
|
`
|
2018-10-10 17:17:04 -06:00
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
2018-11-20 13:24:09 -07:00
|
|
|
"foo/bar/baz/x.go": "package bar \n const X = 1",
|
|
|
|
"test/t.go": input,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.processTest(t, "foo.com", "test/t.go", nil, nil, want)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that an existing import with badly mismatched path/name has its name
|
|
|
|
// correctly added. See #28645 and #29041.
|
|
|
|
func TestAddNameToMismatchedImport(t *testing.T) {
|
|
|
|
const input = `package main
|
|
|
|
|
|
|
|
import (
|
2019-01-10 10:51:27 -07:00
|
|
|
"foo.com/a.thing"
|
2018-11-20 13:24:09 -07:00
|
|
|
"foo.com/surprise"
|
|
|
|
"foo.com/v1"
|
2019-01-10 10:51:27 -07:00
|
|
|
"foo.com/other/v2"
|
|
|
|
"foo.com/other/v3"
|
|
|
|
"foo.com/go-thing"
|
|
|
|
"foo.com/go-wrong"
|
2018-11-20 13:24:09 -07:00
|
|
|
)
|
|
|
|
|
2019-01-10 10:51:27 -07:00
|
|
|
var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}`
|
2018-11-20 13:24:09 -07:00
|
|
|
|
|
|
|
const want = `package main
|
|
|
|
|
|
|
|
import (
|
2019-01-10 10:51:27 -07:00
|
|
|
"foo.com/a.thing"
|
|
|
|
"foo.com/go-thing"
|
|
|
|
gow "foo.com/go-wrong"
|
|
|
|
v2 "foo.com/other/v2"
|
|
|
|
"foo.com/other/v3"
|
2018-11-20 13:24:09 -07:00
|
|
|
bar "foo.com/surprise"
|
|
|
|
v1 "foo.com/v1"
|
|
|
|
)
|
|
|
|
|
2019-01-10 10:51:27 -07:00
|
|
|
var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}
|
2018-11-20 13:24:09 -07:00
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
2019-01-10 10:51:27 -07:00
|
|
|
"a.thing/a.go": "package a \n const A = 1",
|
2018-11-20 13:24:09 -07:00
|
|
|
"surprise/x.go": "package bar \n const X = 1",
|
|
|
|
"v1/x.go": "package v1 \n const Y = 1",
|
2019-01-10 10:51:27 -07:00
|
|
|
"other/v2/y.go": "package v2 \n const V2 = 1",
|
|
|
|
"other/v3/z.go": "package other \n const V3 = 1",
|
|
|
|
"go-thing/b.go": "package thing \n const Thing = 1",
|
|
|
|
"go-wrong/b.go": "package gow \n const Wrong = 1",
|
2018-11-20 13:24:09 -07:00
|
|
|
"test/t.go": input,
|
2018-10-22 15:56:19 -06:00
|
|
|
},
|
2018-10-10 17:17:04 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "foo.com", "test/t.go", nil, nil, want)
|
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-21 19:35:08 -06:00
|
|
|
// Tests that the LocalPrefix option causes imports
|
|
|
|
// to be added into a later group (num=3).
|
|
|
|
func TestLocalPrefix(t *testing.T) {
|
2017-12-23 01:05:04 -07:00
|
|
|
tests := []struct {
|
2018-10-26 12:54:05 -06:00
|
|
|
name string
|
2018-10-22 15:56:19 -06:00
|
|
|
modules []packagestest.Module
|
2017-12-23 01:05:04 -07:00
|
|
|
localPrefix string
|
|
|
|
src string
|
|
|
|
want string
|
|
|
|
}{
|
|
|
|
{
|
2018-10-26 12:54:05 -06:00
|
|
|
name: "one_local",
|
2018-10-22 15:56:19 -06:00
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"bar/bar.go": "package bar \n const X = 1",
|
|
|
|
},
|
2017-12-23 01:05:04 -07:00
|
|
|
},
|
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
localPrefix: "foo.com/",
|
2017-12-23 01:05:04 -07:00
|
|
|
src: "package main \n const Y = bar.X \n const _ = runtime.GOOS",
|
|
|
|
want: `package main
|
2016-07-21 19:35:08 -06:00
|
|
|
|
2017-12-23 01:05:04 -07:00
|
|
|
import (
|
|
|
|
"runtime"
|
|
|
|
|
2018-10-22 15:56:19 -06:00
|
|
|
"foo.com/bar"
|
2017-12-23 01:05:04 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const Y = bar.X
|
|
|
|
const _ = runtime.GOOS
|
2018-03-13 15:48:25 -06:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
{
|
2018-10-26 12:54:05 -06:00
|
|
|
name: "two_local",
|
2018-10-22 15:56:19 -06:00
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"foo/foo.go": "package foo \n const X = 1",
|
|
|
|
"foo/bar/bar.go": "package bar \n const X = 1",
|
|
|
|
},
|
2018-03-13 15:48:25 -06:00
|
|
|
},
|
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
localPrefix: "foo.com/foo",
|
2018-03-13 15:48:25 -06:00
|
|
|
src: "package main \n const Y = bar.X \n const Z = foo.X \n const _ = runtime.GOOS",
|
|
|
|
want: `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"runtime"
|
|
|
|
|
2018-10-22 15:56:19 -06:00
|
|
|
"foo.com/foo"
|
|
|
|
"foo.com/foo/bar"
|
2018-03-13 15:48:25 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
const Y = bar.X
|
|
|
|
const Z = foo.X
|
|
|
|
const _ = runtime.GOOS
|
2017-12-23 01:05:04 -07:00
|
|
|
`,
|
2016-07-21 19:35:08 -06:00
|
|
|
},
|
2017-12-23 01:05:04 -07:00
|
|
|
{
|
2018-10-26 12:54:05 -06:00
|
|
|
name: "three_prefixes",
|
2018-10-22 15:56:19 -06:00
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "example.org/pkg",
|
|
|
|
Files: fm{"pkg.go": "package pkg \n const A = 1"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{"bar/bar.go": "package bar \n const B = 1"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "code.org/r/p",
|
|
|
|
Files: fm{"expproj/expproj.go": "package expproj \n const C = 1"},
|
2017-12-23 01:05:04 -07:00
|
|
|
},
|
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
localPrefix: "example.org/pkg,foo.com/,code.org",
|
2017-12-23 01:05:04 -07:00
|
|
|
src: "package main \n const X = pkg.A \n const Y = bar.B \n const Z = expproj.C \n const _ = runtime.GOOS",
|
|
|
|
want: `package main
|
2016-07-21 19:35:08 -06:00
|
|
|
|
|
|
|
import (
|
|
|
|
"runtime"
|
|
|
|
|
2017-12-23 01:05:04 -07:00
|
|
|
"code.org/r/p/expproj"
|
|
|
|
"example.org/pkg"
|
2018-10-22 15:56:19 -06:00
|
|
|
"foo.com/bar"
|
2016-07-21 19:35:08 -06:00
|
|
|
)
|
|
|
|
|
2017-12-23 01:05:04 -07:00
|
|
|
const X = pkg.A
|
|
|
|
const Y = bar.B
|
|
|
|
const Z = expproj.C
|
2016-07-21 19:35:08 -06:00
|
|
|
const _ = runtime.GOOS
|
2017-12-23 01:05:04 -07:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
2018-10-26 12:54:05 -06:00
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
testConfig{
|
|
|
|
// The module being processed has to be first so it's the primary module.
|
|
|
|
modules: append([]packagestest.Module{{
|
|
|
|
Name: "test.com",
|
|
|
|
Files: fm{"t.go": tt.src},
|
|
|
|
}}, tt.modules...),
|
|
|
|
}.test(t, func(t *goimportTest) {
|
2019-05-06 13:37:46 -06:00
|
|
|
t.env.LocalPrefix = tt.localPrefix
|
|
|
|
t.assertProcessEquals("test.com", "t.go", nil, nil, tt.want)
|
2018-10-26 12:54:05 -06:00
|
|
|
})
|
2017-12-23 01:05:04 -07:00
|
|
|
})
|
|
|
|
}
|
2016-07-21 19:35:08 -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
|
|
|
// Tests that "package documentation" files are ignored.
|
|
|
|
func TestIgnoreDocumentationPackage(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package x
|
|
|
|
|
|
|
|
const Y = foo.X
|
|
|
|
`
|
|
|
|
const want = `package x
|
|
|
|
|
2018-10-22 15:56:19 -06:00
|
|
|
import "foo.com/foo"
|
2018-10-10 17:17:04 -06:00
|
|
|
|
|
|
|
const Y = foo.X
|
|
|
|
`
|
|
|
|
|
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
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"foo/foo.go": "package foo\nconst X = 1\n",
|
|
|
|
"foo/doc.go": "package documentation \n // just to confuse things\n",
|
|
|
|
"x/x.go": input,
|
|
|
|
},
|
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-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "foo.com", "x/x.go", nil, nil, want)
|
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-07 15:40:17 -07:00
|
|
|
// Tests importPathToNameGoPathParse and in particular that it stops
|
|
|
|
// after finding the first non-documentation package name, not
|
|
|
|
// reporting an error on inconsistent package names (since it should
|
|
|
|
// never make it that far).
|
|
|
|
func TestImportPathToNameGoPathParse(t *testing.T) {
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "example.net/pkg",
|
|
|
|
Files: fm{
|
|
|
|
"doc.go": "package documentation\n", // ignored
|
|
|
|
"gen.go": "package main\n", // also ignored
|
|
|
|
"pkg.go": "package the_pkg_name_to_find\n and this syntax error is ignored because of parser.PackageClauseOnly",
|
|
|
|
"z.go": "package inconsistent\n", // inconsistent but ignored
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.test(t, func(t *goimportTest) {
|
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 strings.Contains(t.Name(), "GoPackages") {
|
|
|
|
t.Skip("go/packages does not ignore package main")
|
|
|
|
}
|
2019-07-03 13:23:05 -06:00
|
|
|
r := t.env.GetResolver()
|
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
|
|
|
srcDir := filepath.Dir(t.exported.File("example.net/pkg", "z.go"))
|
|
|
|
names, err := r.loadPackageNames([]string{"example.net/pkg"}, srcDir)
|
2018-11-07 15:40:17 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
const want = "the_pkg_name_to_find"
|
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 got := names["example.net/pkg"]; got != want {
|
|
|
|
t.Errorf("loadPackageNames(..) = %q; want %q", got, want)
|
2018-11-07 15:40:17 -07:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-07-15 12:28:37 -06:00
|
|
|
func TestIgnoreConfiguration(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package x
|
|
|
|
|
|
|
|
const _ = pkg.X
|
|
|
|
`
|
|
|
|
const want = `package x
|
|
|
|
|
2018-10-22 15:56:19 -06:00
|
|
|
import "foo.com/otherwise-longer-so-worse-example/foo/pkg"
|
2018-10-10 17:17:04 -06:00
|
|
|
|
|
|
|
const _ = pkg.X
|
|
|
|
`
|
|
|
|
|
2016-07-15 12:28:37 -06:00
|
|
|
testConfig{
|
2018-10-26 12:54:05 -06:00
|
|
|
gopathOnly: true,
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"../.goimportsignore": "# comment line\n\n foo.com/example", // tests comment, blank line, whitespace trimming
|
|
|
|
"example/pkg/pkg.go": "package pkg\nconst X = 1",
|
|
|
|
"otherwise-longer-so-worse-example/foo/pkg/pkg.go": "package pkg\nconst X = 1",
|
|
|
|
"x/x.go": input,
|
|
|
|
},
|
2016-07-15 12:28:37 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "foo.com", "x/x.go", nil, nil, want)
|
2016-07-15 12:28:37 -06:00
|
|
|
}
|
|
|
|
|
2016-07-18 22:42:54 -06:00
|
|
|
// Skip "node_modules" directory.
|
|
|
|
func TestSkipNodeModules(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package x
|
|
|
|
|
|
|
|
const _ = pkg.X
|
|
|
|
`
|
|
|
|
const want = `package x
|
|
|
|
|
2018-10-22 15:56:19 -06:00
|
|
|
import "foo.com/otherwise-longer/not_modules/pkg"
|
2018-10-10 17:17:04 -06:00
|
|
|
|
|
|
|
const _ = pkg.X
|
|
|
|
`
|
|
|
|
|
2016-07-18 22:42:54 -06:00
|
|
|
testConfig{
|
2018-10-26 12:54:05 -06:00
|
|
|
gopathOnly: true,
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"example/node_modules/pkg/a.go": "package pkg\nconst X = 1",
|
|
|
|
"otherwise-longer/not_modules/pkg/a.go": "package pkg\nconst X = 1",
|
|
|
|
"x/x.go": input,
|
|
|
|
},
|
2016-07-25 09:05:58 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "foo.com", "x/x.go", nil, nil, want)
|
2016-07-25 09:05:58 -06:00
|
|
|
}
|
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
// Tests that package global variables with the same name and function name as
|
|
|
|
// a function in a separate package do not result in an import which masks
|
|
|
|
// the global variable
|
|
|
|
func TestGlobalImports(t *testing.T) {
|
|
|
|
const usesGlobal = `package pkg
|
2016-05-25 17:35:48 -06:00
|
|
|
|
|
|
|
func doSomething() {
|
|
|
|
t := time.Now()
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2018-10-09 15:32:55 -06:00
|
|
|
const declaresGlobal = `package pkg
|
2016-05-25 17:35:48 -06:00
|
|
|
|
|
|
|
type Time struct{}
|
|
|
|
|
|
|
|
func (t Time) Now() Time {
|
|
|
|
return Time{}
|
|
|
|
}
|
|
|
|
|
|
|
|
var time Time
|
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"pkg/uses.go": usesGlobal,
|
|
|
|
"pkg/global.go": declaresGlobal,
|
|
|
|
},
|
2016-05-25 17:35:48 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "foo.com", "pkg/uses.go", nil, nil, usesGlobal)
|
2016-05-25 17:35:48 -06:00
|
|
|
}
|
|
|
|
|
2018-12-10 11:43:31 -07:00
|
|
|
// Some people put multiple packages' files in the same directory. Globals
|
|
|
|
// declared in other packages should be ignored.
|
|
|
|
func TestGlobalImports_DifferentPackage(t *testing.T) {
|
|
|
|
const declaresGlobal = `package main
|
|
|
|
var fmt int
|
|
|
|
`
|
|
|
|
const input = `package pkg
|
|
|
|
var _ = fmt.Printf
|
|
|
|
`
|
|
|
|
const want = `package pkg
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
var _ = fmt.Printf
|
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"pkg/main.go": declaresGlobal,
|
|
|
|
"pkg/uses.go": input,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
|
|
|
|
}
|
|
|
|
|
2018-12-18 12:53:56 -07:00
|
|
|
func TestGlobalImports_MultipleMains(t *testing.T) {
|
|
|
|
const declaresGlobal = `package main
|
|
|
|
var fmt int
|
|
|
|
`
|
|
|
|
const input = `package main
|
|
|
|
import "fmt"
|
|
|
|
var _, _ = fmt.Printf, bytes.Equal
|
|
|
|
`
|
|
|
|
const want = `package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _, _ = fmt.Printf, bytes.Equal
|
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"pkg/main.go": declaresGlobal,
|
|
|
|
"pkg/uses.go": input,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
|
|
|
|
}
|
|
|
|
|
2017-05-12 14:54:58 -06:00
|
|
|
// Tests that sibling files - other files in the same package - can provide an
|
|
|
|
// import that may not be the default one otherwise.
|
|
|
|
func TestSiblingImports(t *testing.T) {
|
|
|
|
|
|
|
|
// provide is the sibling file that provides the desired import.
|
|
|
|
const provide = `package siblingimporttest
|
|
|
|
|
|
|
|
import "local/log"
|
2017-12-08 07:26:14 -07:00
|
|
|
import "my/bytes"
|
2018-12-10 15:33:17 -07:00
|
|
|
import renamed "fmt"
|
2017-05-12 14:54:58 -06:00
|
|
|
|
|
|
|
func LogSomething() {
|
|
|
|
log.Print("Something")
|
2017-12-08 07:26:14 -07:00
|
|
|
bytes.SomeFunc()
|
2018-12-10 15:33:17 -07:00
|
|
|
renamed.Println("Something")
|
2017-05-12 14:54:58 -06:00
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
// need is the file being tested that needs the import.
|
|
|
|
const need = `package siblingimporttest
|
|
|
|
|
2017-12-08 07:26:14 -07:00
|
|
|
var _ = bytes.Buffer{}
|
|
|
|
|
2017-05-12 14:54:58 -06:00
|
|
|
func LogSomethingElse() {
|
|
|
|
log.Print("Something else")
|
2018-12-10 15:33:17 -07:00
|
|
|
renamed.Println("Yet another")
|
2017-05-12 14:54:58 -06:00
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
// want is the expected result file
|
|
|
|
const want = `package siblingimporttest
|
|
|
|
|
2017-12-08 07:26:14 -07:00
|
|
|
import (
|
|
|
|
"bytes"
|
2018-12-10 15:33:17 -07:00
|
|
|
renamed "fmt"
|
2017-12-08 07:26:14 -07:00
|
|
|
"local/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _ = bytes.Buffer{}
|
2017-05-12 14:54:58 -06:00
|
|
|
|
|
|
|
func LogSomethingElse() {
|
|
|
|
log.Print("Something else")
|
2018-12-10 15:33:17 -07:00
|
|
|
renamed.Println("Yet another")
|
2017-05-12 14:54:58 -06:00
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"p/needs_import.go": need,
|
|
|
|
"p/provides_import.go": provide,
|
|
|
|
},
|
2017-05-12 14:54:58 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "foo.com", "p/needs_import.go", nil, nil, want)
|
2017-05-12 14:54:58 -06:00
|
|
|
}
|
|
|
|
|
2018-12-12 11:11:39 -07:00
|
|
|
// Tests #29180: a sibling import of the right package with the wrong name is used.
|
|
|
|
func TestSiblingImport_Misnamed(t *testing.T) {
|
|
|
|
const sibling = `package main
|
|
|
|
import renamed "fmt"
|
|
|
|
var _ = renamed.Printf
|
|
|
|
`
|
|
|
|
const input = `package pkg
|
|
|
|
var _ = fmt.Printf
|
|
|
|
`
|
|
|
|
const want = `package pkg
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
var _ = fmt.Printf
|
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"pkg/main.go": sibling,
|
|
|
|
"pkg/uses.go": input,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-03-31 06:03:24 -06:00
|
|
|
// Tests that an input file's own package is ignored.
|
|
|
|
func TestIgnoreOwnPackage(t *testing.T) {
|
|
|
|
const input = `package pkg
|
|
|
|
|
|
|
|
const _ = pkg.X
|
|
|
|
`
|
|
|
|
const want = `package pkg
|
|
|
|
|
|
|
|
const _ = pkg.X
|
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"pkg/a.go": "package pkg\nconst X = 1",
|
|
|
|
"pkg/b.go": input,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.processTest(t, "foo.com", "pkg/b.go", nil, nil, want)
|
|
|
|
}
|
|
|
|
|
2019-06-07 15:21:57 -06:00
|
|
|
func TestExternalTestImportsPackageUnderTest(t *testing.T) {
|
|
|
|
const provide = `package pkg
|
|
|
|
func DoIt(){}
|
|
|
|
`
|
|
|
|
const input = `package pkg_test
|
|
|
|
|
|
|
|
var _ = pkg.DoIt`
|
|
|
|
|
|
|
|
const want = `package pkg_test
|
|
|
|
|
|
|
|
import "foo.com/pkg"
|
|
|
|
|
|
|
|
var _ = pkg.DoIt
|
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"pkg/provide.go": provide,
|
|
|
|
"pkg/x_test.go": input,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.processTest(t, "foo.com", "pkg/x_test.go", nil, nil, want)
|
|
|
|
}
|
|
|
|
|
2016-07-18 15:58:52 -06:00
|
|
|
func TestPkgIsCandidate(t *testing.T) {
|
2018-10-09 15:32:55 -06:00
|
|
|
tests := []struct {
|
|
|
|
name string
|
2016-07-18 15:58:52 -06:00
|
|
|
filename string
|
|
|
|
pkgIdent string
|
|
|
|
pkg *pkg
|
|
|
|
want bool
|
|
|
|
}{
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "normal_match",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/my/pkg/pkg.go",
|
|
|
|
pkgIdent: "client",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/client",
|
|
|
|
importPathShort: "client",
|
|
|
|
},
|
|
|
|
want: true,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "no_match",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/my/pkg/pkg.go",
|
|
|
|
pkgIdent: "zzz",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/client",
|
|
|
|
importPathShort: "client",
|
|
|
|
},
|
|
|
|
want: false,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "match_too_early",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/my/pkg/pkg.go",
|
|
|
|
pkgIdent: "client",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/client/foo/foo/foo",
|
|
|
|
importPathShort: "client/foo/foo",
|
|
|
|
},
|
|
|
|
want: false,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "substring_match",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/my/pkg/pkg.go",
|
|
|
|
pkgIdent: "client",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/foo/go-client",
|
|
|
|
importPathShort: "foo/go-client",
|
|
|
|
},
|
|
|
|
want: true,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "hidden_internal",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/my/pkg/pkg.go",
|
|
|
|
pkgIdent: "client",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/foo/internal/client",
|
|
|
|
importPathShort: "foo/internal/client",
|
|
|
|
},
|
|
|
|
want: false,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "visible_internal",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/foo/bar.go",
|
|
|
|
pkgIdent: "client",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/foo/internal/client",
|
|
|
|
importPathShort: "foo/internal/client",
|
|
|
|
},
|
|
|
|
want: true,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "invisible_vendor",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/foo/bar.go",
|
|
|
|
pkgIdent: "client",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/other/vendor/client",
|
|
|
|
importPathShort: "client",
|
|
|
|
},
|
|
|
|
want: false,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "visible_vendor",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/foo/bar.go",
|
|
|
|
pkgIdent: "client",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/foo/vendor/client",
|
|
|
|
importPathShort: "client",
|
|
|
|
},
|
|
|
|
want: true,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "match_with_hyphens",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/foo/bar.go",
|
|
|
|
pkgIdent: "socketio",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/foo/socket-io",
|
|
|
|
importPathShort: "foo/socket-io",
|
|
|
|
},
|
|
|
|
want: true,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "match_with_mixed_case",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/foo/bar.go",
|
|
|
|
pkgIdent: "fooprod",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/foo/FooPROD",
|
|
|
|
importPathShort: "foo/FooPROD",
|
|
|
|
},
|
|
|
|
want: true,
|
|
|
|
},
|
2018-10-09 15:32:55 -06:00
|
|
|
{
|
|
|
|
name: "matches_with_hyphen_and_caps",
|
2016-07-18 15:58:52 -06:00
|
|
|
filename: "/gopath/src/foo/bar.go",
|
|
|
|
pkgIdent: "fooprod",
|
|
|
|
pkg: &pkg{
|
|
|
|
dir: "/gopath/src/foo/Foo-PROD",
|
|
|
|
importPathShort: "foo/Foo-PROD",
|
|
|
|
},
|
|
|
|
want: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for i, tt := range tests {
|
2018-10-09 15:32:55 -06:00
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2019-12-26 17:13:58 -07:00
|
|
|
refs := references{tt.pkgIdent: nil}
|
|
|
|
got := pkgIsCandidate(tt.filename, refs, tt.pkg)
|
2018-10-09 15:32:55 -06:00
|
|
|
if got != tt.want {
|
|
|
|
t.Errorf("test %d. pkgIsCandidate(%q, %q, %+v) = %v; want %v",
|
|
|
|
i, tt.filename, tt.pkgIdent, *tt.pkg, got, tt.want)
|
|
|
|
}
|
|
|
|
})
|
2016-07-18 15:58:52 -06:00
|
|
|
}
|
|
|
|
}
|
2017-03-08 15:01:44 -07:00
|
|
|
|
2017-07-07 10:16:50 -06:00
|
|
|
// Issue 20941: this used to panic on Windows.
|
|
|
|
func TestProcessStdin(t *testing.T) {
|
2019-05-06 13:37:46 -06:00
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
},
|
|
|
|
}.test(t, func(t *goimportTest) {
|
|
|
|
got, err := t.processNonModule("<standard input>", []byte("package main\nfunc main() {\n\tfmt.Println(123)\n}\n"), nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !strings.Contains(string(got), `"fmt"`) {
|
|
|
|
t.Errorf("expected fmt import; got: %s", got)
|
|
|
|
}
|
|
|
|
})
|
2017-07-07 10:16:50 -06:00
|
|
|
}
|
2017-02-15 06:46:03 -07:00
|
|
|
|
|
|
|
// Tests LocalPackagePromotion when there is a local package that matches, it
|
|
|
|
// should be the closest match.
|
|
|
|
// https://golang.org/issues/17557
|
|
|
|
func TestLocalPackagePromotion(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package main
|
|
|
|
var c = &config.SystemConfig{}
|
|
|
|
`
|
|
|
|
const want = `package main
|
|
|
|
|
|
|
|
import "mycompany.net/tool/config"
|
|
|
|
|
|
|
|
var c = &config.SystemConfig{}
|
|
|
|
`
|
|
|
|
|
2017-02-15 06:46:03 -07:00
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "config.net/config",
|
|
|
|
Files: fm{"config.go": "package config\n type SystemConfig struct {}"}, // Will match but should not be first choice
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "mycompany.net/config",
|
|
|
|
Files: fm{"config.go": "package config\n type SystemConfig struct {}"}, // Will match but should not be first choice
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "mycompany.net/tool",
|
|
|
|
Files: fm{
|
|
|
|
"config/config.go": "package config\n type SystemConfig struct {}", // Local package should be promoted over shorter package
|
|
|
|
"main.go": input,
|
|
|
|
},
|
|
|
|
},
|
2017-02-15 06:46:03 -07:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want)
|
2017-02-15 06:46:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tests FindImportInLocalGoFiles looks at the import lines for other Go files in the
|
|
|
|
// local directory, since the user is likely to import the same packages in the current
|
|
|
|
// Go file. If an import is found that satisfies the need, it should be used over the
|
|
|
|
// standard library.
|
|
|
|
// https://golang.org/issues/17557
|
|
|
|
func TestFindImportInLocalGoFiles(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package main
|
|
|
|
var _ = &bytes.Buffer{}`
|
|
|
|
|
|
|
|
const want = `package main
|
2017-02-15 06:46:03 -07:00
|
|
|
|
|
|
|
import "bytes.net/bytes"
|
|
|
|
|
|
|
|
var _ = &bytes.Buffer{}
|
|
|
|
`
|
2018-10-10 17:17:04 -06:00
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "mycompany.net/tool",
|
|
|
|
Files: fm{
|
|
|
|
"io.go": "package main\n import \"bytes.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains package import that will cause stdlib to be ignored
|
|
|
|
"main.go": input,
|
|
|
|
},
|
|
|
|
},
|
2018-10-26 12:54:05 -06:00
|
|
|
{
|
|
|
|
Name: "bytes.net/bytes",
|
|
|
|
Files: fm{"bytes.go": "package bytes\n type Buffer struct {}"}, // Should be selected over standard library
|
|
|
|
},
|
2018-10-10 17:17:04 -06:00
|
|
|
},
|
2018-10-22 15:56:19 -06:00
|
|
|
}.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want)
|
2017-02-15 06:46:03 -07:00
|
|
|
}
|
|
|
|
|
2018-10-26 12:54:05 -06:00
|
|
|
func TestInMemoryFile(t *testing.T) {
|
|
|
|
const input = `package main
|
|
|
|
var _ = &bytes.Buffer{}`
|
|
|
|
|
|
|
|
const want = `package main
|
|
|
|
|
|
|
|
import "bytes"
|
|
|
|
|
|
|
|
var _ = &bytes.Buffer{}
|
|
|
|
`
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{"x.go": "package x\n"},
|
|
|
|
},
|
|
|
|
}.processTest(t, "foo.com", "x.go", []byte(input), nil, want)
|
|
|
|
}
|
|
|
|
|
2017-02-15 06:46:03 -07:00
|
|
|
func TestImportNoGoFiles(t *testing.T) {
|
2018-10-10 17:17:04 -06:00
|
|
|
const input = `package main
|
|
|
|
var _ = &bytes.Buffer{}`
|
|
|
|
|
|
|
|
const want = `package main
|
2017-02-15 06:46:03 -07:00
|
|
|
|
|
|
|
import "bytes"
|
|
|
|
|
|
|
|
var _ = &bytes.Buffer{}
|
|
|
|
`
|
2019-05-06 13:37:46 -06:00
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "mycompany.net",
|
|
|
|
},
|
|
|
|
}.test(t, func(t *goimportTest) {
|
|
|
|
buf, err := t.processNonModule("mycompany.net/tool/main.go", []byte(input), nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Process() = %v", err)
|
|
|
|
}
|
|
|
|
if string(buf) != want {
|
|
|
|
t.Errorf("Got:\n%s\nWant:\n%s", buf, want)
|
|
|
|
}
|
|
|
|
})
|
2018-10-10 17:17:04 -06:00
|
|
|
|
2017-02-15 06:46:03 -07:00
|
|
|
}
|
2017-12-15 06:15:17 -07:00
|
|
|
|
|
|
|
// Ensures a token as large as 500000 bytes can be handled
|
|
|
|
// https://golang.org/issues/18201
|
|
|
|
func TestProcessLargeToken(t *testing.T) {
|
|
|
|
largeString := strings.Repeat("x", 500000)
|
|
|
|
|
2018-10-10 17:17:04 -06:00
|
|
|
input := `package testimports
|
2017-12-15 06:15:17 -07:00
|
|
|
|
|
|
|
import (
|
2018-10-26 12:54:05 -06:00
|
|
|
"bytes"
|
2017-12-15 06:15:17 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const s = fmt.Sprintf("%s", "` + largeString + `")
|
2018-10-26 12:54:05 -06:00
|
|
|
var _ = bytes.Buffer{}
|
2017-12-15 06:15:17 -07:00
|
|
|
|
|
|
|
// end
|
|
|
|
`
|
|
|
|
|
|
|
|
want := `package testimports
|
|
|
|
|
|
|
|
import (
|
2018-10-26 12:54:05 -06:00
|
|
|
"bytes"
|
2017-12-15 06:15:17 -07:00
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
const s = fmt.Sprintf("%s", "` + largeString + `")
|
2018-10-26 12:54:05 -06:00
|
|
|
|
|
|
|
var _ = bytes.Buffer{}
|
2017-12-15 06:15:17 -07:00
|
|
|
|
|
|
|
// end
|
|
|
|
`
|
2018-10-10 17:17:04 -06:00
|
|
|
|
|
|
|
testConfig{
|
2018-10-22 15:56:19 -06:00
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{"foo.go": input},
|
|
|
|
},
|
|
|
|
}.processTest(t, "foo.com", "foo.go", nil, nil, want)
|
2017-12-15 06:15:17 -07:00
|
|
|
}
|
2019-08-12 15:50:58 -06:00
|
|
|
|
2020-01-03 16:01:15 -07:00
|
|
|
// Tests that an external test package will import the package under test if it
|
|
|
|
// also uses symbols exported only in test files.
|
|
|
|
// https://golang.org/issues/29979
|
|
|
|
func TestExternalTest(t *testing.T) {
|
|
|
|
const input = `package a_test
|
|
|
|
func TestX() {
|
|
|
|
a.X()
|
|
|
|
a.Y()
|
|
|
|
}
|
|
|
|
`
|
|
|
|
const want = `package a_test
|
|
|
|
|
|
|
|
import "foo.com/a"
|
|
|
|
|
|
|
|
func TestX() {
|
|
|
|
a.X()
|
|
|
|
a.Y()
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
testConfig{
|
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "foo.com/a",
|
|
|
|
Files: fm{
|
|
|
|
"a.go": "package a\n func X() {}",
|
|
|
|
"export_test.go": "package a\n func Y() {}",
|
|
|
|
"a_test.go": input,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.processTest(t, "foo.com/a", "a_test.go", nil, nil, want)
|
|
|
|
}
|
|
|
|
|
2019-08-12 15:50:58 -06:00
|
|
|
// TestStdLibGetCandidates tests that get packages finds std library packages
|
|
|
|
// with correct priorities.
|
2019-10-04 13:38:18 -06:00
|
|
|
func TestGetCandidates(t *testing.T) {
|
|
|
|
type res struct {
|
2019-12-27 13:46:49 -07:00
|
|
|
relevance int
|
2019-10-04 13:38:18 -06:00
|
|
|
name, path string
|
|
|
|
}
|
|
|
|
want := []res{
|
2019-12-27 13:46:49 -07:00
|
|
|
{0, "bytes", "bytes"},
|
|
|
|
{0, "http", "net/http"},
|
|
|
|
{0, "rand", "crypto/rand"},
|
|
|
|
{0, "bar", "bar.com/bar"},
|
|
|
|
{0, "foo", "foo.com/foo"},
|
2019-08-12 15:50:58 -06:00
|
|
|
}
|
|
|
|
|
2019-10-04 13:38:18 -06:00
|
|
|
testConfig{
|
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{"foo/foo.go": "package foo\n"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "bar.com",
|
|
|
|
Files: fm{"bar/bar.go": "package bar\n"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.test(t, func(t *goimportTest) {
|
2019-12-27 13:46:49 -07:00
|
|
|
var mu sync.Mutex
|
2019-10-04 13:38:18 -06:00
|
|
|
var got []res
|
2019-12-27 13:46:49 -07:00
|
|
|
add := func(c ImportFix) {
|
|
|
|
mu.Lock()
|
|
|
|
defer mu.Unlock()
|
2019-10-04 13:38:18 -06:00
|
|
|
for _, w := range want {
|
|
|
|
if c.StmtInfo.ImportPath == w.path {
|
2019-12-27 13:46:49 -07:00
|
|
|
got = append(got, res{c.Relevance, c.IdentName, c.StmtInfo.ImportPath})
|
2019-10-04 13:38:18 -06:00
|
|
|
}
|
|
|
|
}
|
2019-08-12 15:50:58 -06:00
|
|
|
}
|
2019-12-30 14:18:34 -07:00
|
|
|
if err := getAllCandidates(context.Background(), add, "", "x.go", "x", t.env); err != nil {
|
2019-12-27 13:46:49 -07:00
|
|
|
t.Fatalf("GetAllCandidates() = %v", err)
|
|
|
|
}
|
|
|
|
// Sort, then clear out relevance so it doesn't mess up the DeepEqual.
|
|
|
|
sort.Slice(got, func(i, j int) bool {
|
|
|
|
ri, rj := got[i], got[j]
|
|
|
|
if ri.relevance != rj.relevance {
|
|
|
|
return ri.relevance > rj.relevance // Highest first.
|
|
|
|
}
|
|
|
|
return ri.name < rj.name
|
|
|
|
})
|
|
|
|
for i := range got {
|
|
|
|
got[i].relevance = 0
|
|
|
|
}
|
2019-10-04 13:38:18 -06:00
|
|
|
if !reflect.DeepEqual(want, got) {
|
|
|
|
t.Errorf("wanted stdlib results in order %v, got %v", want, got)
|
|
|
|
}
|
|
|
|
})
|
2019-08-12 15:50:58 -06:00
|
|
|
}
|
2019-10-13 15:23:09 -06:00
|
|
|
|
2019-10-30 17:30:14 -06:00
|
|
|
func TestGetPackageCompletions(t *testing.T) {
|
|
|
|
type res struct {
|
2019-12-27 13:46:49 -07:00
|
|
|
relevance int
|
2019-10-30 17:30:14 -06:00
|
|
|
name, path, symbol string
|
|
|
|
}
|
|
|
|
want := []res{
|
2019-12-27 13:46:49 -07:00
|
|
|
{0, "rand", "math/rand", "Seed"},
|
|
|
|
{0, "rand", "bar.com/rand", "Bar"},
|
2019-10-30 17:30:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
testConfig{
|
|
|
|
modules: []packagestest.Module{
|
|
|
|
{
|
|
|
|
Name: "bar.com",
|
|
|
|
Files: fm{"rand/bar.go": "package rand\nvar Bar int\n"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.test(t, func(t *goimportTest) {
|
2019-12-27 13:46:49 -07:00
|
|
|
var mu sync.Mutex
|
2019-10-30 17:30:14 -06:00
|
|
|
var got []res
|
2019-12-27 13:46:49 -07:00
|
|
|
add := func(c PackageExport) {
|
|
|
|
mu.Lock()
|
|
|
|
defer mu.Unlock()
|
2019-10-30 17:30:14 -06:00
|
|
|
for _, csym := range c.Exports {
|
|
|
|
for _, w := range want {
|
|
|
|
if c.Fix.StmtInfo.ImportPath == w.path && csym == w.symbol {
|
2019-12-27 13:46:49 -07:00
|
|
|
got = append(got, res{c.Fix.Relevance, c.Fix.IdentName, c.Fix.StmtInfo.ImportPath, csym})
|
2019-10-30 17:30:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-30 14:18:34 -07:00
|
|
|
if err := getPackageExports(context.Background(), add, "rand", "x.go", "x", t.env); err != nil {
|
2019-12-27 13:46:49 -07:00
|
|
|
t.Fatalf("getPackageCompletions() = %v", err)
|
|
|
|
}
|
|
|
|
// Sort, then clear out relevance so it doesn't mess up the DeepEqual.
|
|
|
|
sort.Slice(got, func(i, j int) bool {
|
|
|
|
ri, rj := got[i], got[j]
|
|
|
|
if ri.relevance != rj.relevance {
|
|
|
|
return ri.relevance > rj.relevance // Highest first.
|
|
|
|
}
|
|
|
|
return ri.name < rj.name
|
|
|
|
})
|
|
|
|
for i := range got {
|
|
|
|
got[i].relevance = 0
|
|
|
|
}
|
2019-10-30 17:30:14 -06:00
|
|
|
if !reflect.DeepEqual(want, got) {
|
|
|
|
t.Errorf("wanted stdlib results in order %v, got %v", want, got)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-10-13 15:23:09 -06:00
|
|
|
// Tests #34895: process should not panic on concurrent calls.
|
|
|
|
func TestConcurrentProcess(t *testing.T) {
|
|
|
|
testConfig{
|
|
|
|
module: packagestest.Module{
|
|
|
|
Name: "foo.com",
|
|
|
|
Files: fm{
|
|
|
|
"p/first.go": `package foo
|
|
|
|
|
|
|
|
func _() {
|
|
|
|
fmt.Println()
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
"p/second.go": `package foo
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
func _() {
|
|
|
|
fmt.Println()
|
|
|
|
imports.Bar() // not imported.
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}.test(t, func(t *goimportTest) {
|
|
|
|
var (
|
|
|
|
n = 10
|
|
|
|
wg sync.WaitGroup
|
|
|
|
)
|
|
|
|
wg.Add(n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
_, err := t.process("foo.com", "p/first.go", nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
})
|
|
|
|
}
|