Commit 29461ccc authored by Robert Griesemer's avatar Robert Griesemer

go/parser: simplify code to read from an io.Reader (cleanup)

ioutil.ReadAll didn't exist when we wrote that parser code
originally (in 2009). Now it does, so use it. This may also
make that code path slightly more efficient.

Also, now that we are guaranteed to have a fast path for reading
from an io.Reader (and thus an io.ReadCloser), simplify setup
code for parser.ParseFile calls in srcimporter.Importer.ParseFiles.

Remove the associated TODO since we cannot reproduce any significant
performance differences when running go test -run ImportStdLib for
the case where we used to read directly from a file (even before the
change to the parser).

Fixes #19281.

Change-Id: I816459d092bb9e27fdc85089b8f21d57ec3fd79a
Reviewed-on: https://go-review.googlesource.com/85395Reviewed-by: 's avatarAlan Donovan <adonovan@google.com>
parent ea012d10
...@@ -223,7 +223,7 @@ var pkgDeps = map[string][]string{ ...@@ -223,7 +223,7 @@ var pkgDeps = map[string][]string{
"go/importer": {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"}, "go/importer": {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"},
"go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"}, "go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
"go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"}, "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"},
"go/internal/srcimporter": {"L4", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"}, "go/internal/srcimporter": {"L4", "OS", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"},
"go/types": {"L4", "GOPARSER", "container/heap", "go/constant"}, "go/types": {"L4", "GOPARSER", "container/heap", "go/constant"},
// One of a kind. // One of a kind.
......
...@@ -13,6 +13,8 @@ import ( ...@@ -13,6 +13,8 @@ import (
"go/parser" "go/parser"
"go/token" "go/token"
"go/types" "go/types"
"io"
"os"
"path/filepath" "path/filepath"
"sync" "sync"
) )
...@@ -162,7 +164,11 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type ...@@ -162,7 +164,11 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
} }
func (p *Importer) parseFiles(dir string, filenames []string) ([]*ast.File, error) { func (p *Importer) parseFiles(dir string, filenames []string) ([]*ast.File, error) {
open := p.ctxt.OpenFile // possibly nil // use build.Context's OpenFile if there is one
open := p.ctxt.OpenFile
if open == nil {
open = func(name string) (io.ReadCloser, error) { return os.Open(name) }
}
files := make([]*ast.File, len(filenames)) files := make([]*ast.File, len(filenames))
errors := make([]error, len(filenames)) errors := make([]error, len(filenames))
...@@ -172,22 +178,13 @@ func (p *Importer) parseFiles(dir string, filenames []string) ([]*ast.File, erro ...@@ -172,22 +178,13 @@ func (p *Importer) parseFiles(dir string, filenames []string) ([]*ast.File, erro
for i, filename := range filenames { for i, filename := range filenames {
go func(i int, filepath string) { go func(i int, filepath string) {
defer wg.Done() defer wg.Done()
if open != nil {
src, err := open(filepath) src, err := open(filepath)
if err != nil { if err != nil {
errors[i] = fmt.Errorf("opening package file %s failed (%v)", filepath, err) errors[i] = err // open provides operation and filename in error
return return
} }
files[i], errors[i] = parser.ParseFile(p.fset, filepath, src, 0) files[i], errors[i] = parser.ParseFile(p.fset, filepath, src, 0)
src.Close() // ignore Close error - parsing may have succeeded which is all we need src.Close() // ignore Close error - parsing may have succeeded which is all we need
} else {
// Special-case when ctxt doesn't provide a custom OpenFile and use the
// parser's file reading mechanism directly. This appears to be quite a
// bit faster than opening the file and providing an io.ReaderCloser in
// both cases.
// TODO(gri) investigate performance difference (issue #19281)
files[i], errors[i] = parser.ParseFile(p.fset, filepath, nil, 0)
}
}(i, p.joinPath(dir, filename)) }(i, p.joinPath(dir, filename))
} }
wg.Wait() wg.Wait()
......
...@@ -35,11 +35,7 @@ func readSource(filename string, src interface{}) ([]byte, error) { ...@@ -35,11 +35,7 @@ func readSource(filename string, src interface{}) ([]byte, error) {
return s.Bytes(), nil return s.Bytes(), nil
} }
case io.Reader: case io.Reader:
var buf bytes.Buffer return ioutil.ReadAll(s)
if _, err := io.Copy(&buf, s); err != nil {
return nil, err
}
return buf.Bytes(), nil
} }
return nil, errors.New("invalid source") return nil, errors.New("invalid source")
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment