Skip to content

Commit 80182d4

Browse files
committed
go/build: refactor per-file info & reader
Make code cleaner and a bit more adaptable: instead of an ever-growing list of arguments and results for readImports, put everything in a fileInfo struct, and rename function to readGoInfo. (Not a goInfo struct because it gets used for non-Go source files as well, but that processing is much simpler.) The refactoring simplifies the embed work in the next CL, but this CL makes no semantic changes. For #41191. Change-Id: Id2de2a3b8d351adc1c919dcf79dfbe79fc3d5301 Reviewed-on: https://go-review.googlesource.com/c/go/+/243940 Trust: Russ Cox <[email protected]> Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Jay Conrod <[email protected]>
1 parent 7f73669 commit 80182d4

File tree

4 files changed

+145
-111
lines changed

4 files changed

+145
-111
lines changed

src/go/build/build.go

Lines changed: 58 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"fmt"
1111
"go/ast"
1212
"go/doc"
13-
"go/parser"
1413
"go/token"
1514
"internal/goroot"
1615
"internal/goversion"
@@ -812,12 +811,12 @@ Found:
812811
p.InvalidGoFiles = append(p.InvalidGoFiles, name)
813812
}
814813

815-
match, data, filename, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly)
814+
info, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly, fset)
816815
if err != nil {
817816
badFile(err)
818817
continue
819818
}
820-
if !match {
819+
if info == nil {
821820
if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
822821
// not due to build constraints - don't report
823822
} else if ext == ".go" {
@@ -827,6 +826,7 @@ Found:
827826
}
828827
continue
829828
}
829+
data, filename := info.header, info.name
830830

831831
// Going to save the file. For non-Go files, can stop here.
832832
switch ext {
@@ -843,11 +843,11 @@ Found:
843843
continue
844844
}
845845

846-
pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
847-
if err != nil {
848-
badFile(err)
846+
if info.parseErr != nil {
847+
badFile(info.parseErr)
849848
continue
850849
}
850+
pf := info.parsed
851851

852852
pkg := pf.Name.Name
853853
if pkg == "documentation" {
@@ -894,42 +894,17 @@ Found:
894894
}
895895

896896
// Record imports and information about cgo.
897-
type importPos struct {
898-
path string
899-
pos token.Pos
900-
}
901-
var fileImports []importPos
902897
isCgo := false
903-
for _, decl := range pf.Decls {
904-
d, ok := decl.(*ast.GenDecl)
905-
if !ok {
906-
continue
907-
}
908-
for _, dspec := range d.Specs {
909-
spec, ok := dspec.(*ast.ImportSpec)
910-
if !ok {
898+
for _, imp := range info.imports {
899+
if imp.path == "C" {
900+
if isTest {
901+
badFile(fmt.Errorf("use of cgo in test %s not supported", filename))
911902
continue
912903
}
913-
quoted := spec.Path.Value
914-
path, err := strconv.Unquote(quoted)
915-
if err != nil {
916-
panic(fmt.Sprintf("%s: parser returned invalid quoted string: <%s>", filename, quoted))
917-
}
918-
fileImports = append(fileImports, importPos{path, spec.Pos()})
919-
if path == "C" {
920-
if isTest {
921-
badFile(fmt.Errorf("use of cgo in test %s not supported", filename))
922-
} else {
923-
cg := spec.Doc
924-
if cg == nil && len(d.Specs) == 1 {
925-
cg = d.Doc
926-
}
927-
if cg != nil {
928-
if err := ctxt.saveCgo(filename, p, cg); err != nil {
929-
badFile(err)
930-
}
931-
}
932-
isCgo = true
904+
isCgo = true
905+
if imp.doc != nil {
906+
if err := ctxt.saveCgo(filename, p, imp.doc); err != nil {
907+
badFile(err)
933908
}
934909
}
935910
}
@@ -959,7 +934,7 @@ Found:
959934
}
960935
*fileList = append(*fileList, name)
961936
if importMap != nil {
962-
for _, imp := range fileImports {
937+
for _, imp := range info.imports {
963938
importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
964939
}
965940
}
@@ -1309,24 +1284,44 @@ func parseWord(data []byte) (word, rest []byte) {
13091284
// MatchFile considers the name of the file and may use ctxt.OpenFile to
13101285
// read some or all of the file's content.
13111286
func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
1312-
match, _, _, err = ctxt.matchFile(dir, name, nil, nil)
1313-
return
1287+
info, err := ctxt.matchFile(dir, name, nil, nil, nil)
1288+
return info != nil, err
13141289
}
13151290

13161291
var dummyPkg Package
13171292

1293+
// fileInfo records information learned about a file included in a build.
1294+
type fileInfo struct {
1295+
name string // full name including dir
1296+
header []byte
1297+
fset *token.FileSet
1298+
parsed *ast.File
1299+
parseErr error
1300+
imports []fileImport
1301+
}
1302+
1303+
type fileImport struct {
1304+
path string
1305+
pos token.Pos
1306+
doc *ast.CommentGroup
1307+
}
1308+
13181309
// matchFile determines whether the file with the given name in the given directory
13191310
// should be included in the package being constructed.
1320-
// It returns the data read from the file.
1311+
// If the file should be included, matchFile returns a non-nil *fileInfo (and a nil error).
1312+
// Non-nil errors are reserved for unexpected problems.
1313+
//
13211314
// If name denotes a Go program, matchFile reads until the end of the
1322-
// imports (and returns that data) even though it only considers text
1323-
// until the first non-comment.
1315+
// imports and returns that section of the file in the fileInfo's header field,
1316+
// even though it only considers text until the first non-comment
1317+
// for +build lines.
1318+
//
13241319
// If allTags is non-nil, matchFile records any encountered build tag
13251320
// by setting allTags[tag] = true.
1326-
func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binaryOnly *bool) (match bool, data []byte, filename string, err error) {
1321+
func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binaryOnly *bool, fset *token.FileSet) (*fileInfo, error) {
13271322
if strings.HasPrefix(name, "_") ||
13281323
strings.HasPrefix(name, ".") {
1329-
return
1324+
return nil, nil
13301325
}
13311326

13321327
i := strings.LastIndex(name, ".")
@@ -1336,55 +1331,53 @@ func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binary
13361331
ext := name[i:]
13371332

13381333
if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles {
1339-
return
1334+
return nil, nil
13401335
}
13411336

13421337
if ext != ".go" && fileListForExt(&dummyPkg, ext) == nil {
13431338
// skip
1344-
return
1339+
return nil, nil
13451340
}
13461341

1342+
info := &fileInfo{name: ctxt.joinPath(dir, name), fset: fset}
13471343
if ext == ".syso" {
13481344
// binary, no reading
1349-
match = true
1350-
return
1345+
return info, nil
13511346
}
13521347

1353-
filename = ctxt.joinPath(dir, name)
1354-
f, err := ctxt.openFile(filename)
1348+
f, err := ctxt.openFile(info.name)
13551349
if err != nil {
1356-
return
1350+
return nil, err
13571351
}
13581352

1359-
if strings.HasSuffix(filename, ".go") {
1360-
data, err = readImports(f, false, nil)
1361-
if strings.HasSuffix(filename, "_test.go") {
1353+
if strings.HasSuffix(name, ".go") {
1354+
err = readGoInfo(f, info)
1355+
if strings.HasSuffix(name, "_test.go") {
13621356
binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files
13631357
}
13641358
} else {
13651359
binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources
1366-
data, err = readComments(f)
1360+
info.header, err = readComments(f)
13671361
}
13681362
f.Close()
13691363
if err != nil {
1370-
err = fmt.Errorf("read %s: %v", filename, err)
1371-
return
1364+
return nil, fmt.Errorf("read %s: %v", info.name, err)
13721365
}
13731366

13741367
// Look for +build comments to accept or reject the file.
1375-
ok, sawBinaryOnly, err := ctxt.shouldBuild(data, allTags)
1368+
ok, sawBinaryOnly, err := ctxt.shouldBuild(info.header, allTags)
13761369
if err != nil {
1377-
return // non-nil err
1370+
return nil, err
13781371
}
13791372
if !ok && !ctxt.UseAllFiles {
1380-
return // nil err
1373+
return nil, nil
13811374
}
13821375

13831376
if binaryOnly != nil && sawBinaryOnly {
13841377
*binaryOnly = true
13851378
}
1386-
match = true
1387-
return
1379+
1380+
return info, nil
13881381
}
13891382

13901383
func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {

src/go/build/deps_test.go

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"path/filepath"
1818
"runtime"
1919
"sort"
20-
"strconv"
2120
"strings"
2221
"testing"
2322
)
@@ -606,24 +605,22 @@ func findImports(pkg string) ([]string, error) {
606605
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
607606
continue
608607
}
609-
f, err := os.Open(filepath.Join(dir, name))
608+
var info fileInfo
609+
info.name = filepath.Join(dir, name)
610+
f, err := os.Open(info.name)
610611
if err != nil {
611612
return nil, err
612613
}
613-
var imp []string
614-
data, err := readImports(f, false, &imp)
614+
err = readGoInfo(f, &info)
615615
f.Close()
616616
if err != nil {
617617
return nil, fmt.Errorf("reading %v: %v", name, err)
618618
}
619-
if bytes.Contains(data, buildIgnore) {
619+
if bytes.Contains(info.header, buildIgnore) {
620620
continue
621621
}
622-
for _, quoted := range imp {
623-
path, err := strconv.Unquote(quoted)
624-
if err != nil {
625-
continue
626-
}
622+
for _, imp := range info.imports {
623+
path := imp.path
627624
if !haveImport[path] {
628625
haveImport[path] = true
629626
imports = append(imports, path)

0 commit comments

Comments
 (0)