1
0
mirror of https://github.com/golang/go synced 2024-11-18 18:04:46 -07:00

imports: support files with longer lines

This change set fixes the issue by specifying a max buffer size of ~1 megabyte for Scanner.
Previously the max was not set resulting in the default max which is ~64k.  This increased max should not increase
memory use for smaller, normal files because it is a max and the code expands the buffer as needed for large tokens.

The change set includes an additional change to return an error from the Scanner which was ignored previously.

Fixes golang/go#18201

Change-Id: I11be39af74d5eb3b353ad81ba1cb5404207aa65d
Reviewed-on: https://go-review.googlesource.com/83800
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Steve Gilbert 2017-12-15 08:15:17 -05:00 committed by Brad Fitzpatrick
parent ef037a11d2
commit 96b5a5404f
2 changed files with 104 additions and 3 deletions

View File

@ -5,6 +5,7 @@
package imports
import (
"bufio"
"bytes"
"flag"
"go/build"
@ -1957,3 +1958,95 @@ var _ = &bytes.Buffer{}
}
})
}
// A happy path test for Process
func TestProcess(t *testing.T) {
in := `package testimports
var s = fmt.Sprintf("%s", "value")
`
out, err := Process("foo", []byte(in), nil)
if err != nil {
t.Errorf("Process returned error.\n got:\n%v\nwant:\nnil", err)
}
want := `package testimports
import "fmt"
var s = fmt.Sprintf("%s", "value")
`
if got := string(out); got != want {
t.Errorf("Process returned unexpected result.\ngot:\n%v\nwant:\n%v", got, want)
}
}
// 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)
in := `package testimports
import (
"fmt"
"mydomain.mystuff/mypkg"
)
const s = fmt.Sprintf("%s", "` + largeString + `")
const x = mypkg.Sprintf("%s", "my package")
// end
`
out, err := Process("foo", []byte(in), nil)
if err != nil {
t.Errorf("Process returned error.\n got:\n%v\nwant:\nnil", err)
}
want := `package testimports
import (
"fmt"
"mydomain.mystuff/mypkg"
)
const s = fmt.Sprintf("%s", "` + largeString + `")
const x = mypkg.Sprintf("%s", "my package")
// end
`
if got := string(out); got != want {
t.Errorf("Process returned unexpected result.\ngot:\n%v\nwant:\n%v", got, want)
}
}
// Ensures a token that is larger that
// https://golang.org/issues/18201
func TestProcessTokenTooLarge(t *testing.T) {
const largeSize = maxScanTokenSize + 1
largeString := strings.Repeat("x", largeSize)
in := `package testimports
import (
"fmt"
"mydomain.mystuff/mypkg"
)
const s = fmt.Sprintf("%s", "` + largeString + `")
const x = mypkg.Sprintf("%s", "my package")
// end
`
_, err := Process("foo", []byte(in), nil)
if err != bufio.ErrTooLong {
t.Errorf("Process did not returned expected error.\n got:\n%v\nwant:\n%v", err, bufio.ErrTooLong)
}
}

View File

@ -98,7 +98,10 @@ func Process(filename string, src []byte, opt *Options) ([]byte, error) {
out = adjust(src, out)
}
if len(spacesBefore) > 0 {
out = addImportSpaces(bytes.NewReader(out), spacesBefore)
out, err = addImportSpaces(bytes.NewReader(out), spacesBefore)
if err != nil {
return nil, err
}
}
out, err = format.Source(out)
@ -256,9 +259,14 @@ func matchSpace(orig []byte, src []byte) []byte {
var impLine = regexp.MustCompile(`^\s+(?:[\w\.]+\s+)?"(.+)"`)
func addImportSpaces(r io.Reader, breaks []string) []byte {
// Used to set Scanner buffer size so that large tokens can be handled.
// see https://github.com/golang/go/issues/18201
const maxScanTokenSize = bufio.MaxScanTokenSize * 16
func addImportSpaces(r io.Reader, breaks []string) ([]byte, error) {
var out bytes.Buffer
sc := bufio.NewScanner(r)
sc.Buffer(nil, maxScanTokenSize)
inImports := false
done := false
for sc.Scan() {
@ -285,5 +293,5 @@ func addImportSpaces(r io.Reader, breaks []string) []byte {
fmt.Fprintln(&out, s)
}
return out.Bytes()
return out.Bytes(), sc.Err()
}