@@ -10,7 +10,6 @@ import (
10
10
"fmt"
11
11
"go/ast"
12
12
"go/doc"
13
- "go/parser"
14
13
"go/token"
15
14
"internal/goroot"
16
15
"internal/goversion"
@@ -812,12 +811,12 @@ Found:
812
811
p .InvalidGoFiles = append (p .InvalidGoFiles , name )
813
812
}
814
813
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 )
816
815
if err != nil {
817
816
badFile (err )
818
817
continue
819
818
}
820
- if ! match {
819
+ if info == nil {
821
820
if strings .HasPrefix (name , "_" ) || strings .HasPrefix (name , "." ) {
822
821
// not due to build constraints - don't report
823
822
} else if ext == ".go" {
@@ -827,6 +826,7 @@ Found:
827
826
}
828
827
continue
829
828
}
829
+ data , filename := info .header , info .name
830
830
831
831
// Going to save the file. For non-Go files, can stop here.
832
832
switch ext {
@@ -843,11 +843,11 @@ Found:
843
843
continue
844
844
}
845
845
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 )
849
848
continue
850
849
}
850
+ pf := info .parsed
851
851
852
852
pkg := pf .Name .Name
853
853
if pkg == "documentation" {
@@ -894,42 +894,17 @@ Found:
894
894
}
895
895
896
896
// Record imports and information about cgo.
897
- type importPos struct {
898
- path string
899
- pos token.Pos
900
- }
901
- var fileImports []importPos
902
897
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 ))
911
902
continue
912
903
}
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 )
933
908
}
934
909
}
935
910
}
@@ -959,7 +934,7 @@ Found:
959
934
}
960
935
* fileList = append (* fileList , name )
961
936
if importMap != nil {
962
- for _ , imp := range fileImports {
937
+ for _ , imp := range info . imports {
963
938
importMap [imp .path ] = append (importMap [imp .path ], fset .Position (imp .pos ))
964
939
}
965
940
}
@@ -1309,24 +1284,44 @@ func parseWord(data []byte) (word, rest []byte) {
1309
1284
// MatchFile considers the name of the file and may use ctxt.OpenFile to
1310
1285
// read some or all of the file's content.
1311
1286
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
1314
1289
}
1315
1290
1316
1291
var dummyPkg Package
1317
1292
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
+
1318
1309
// matchFile determines whether the file with the given name in the given directory
1319
1310
// 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
+ //
1321
1314
// 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
+ //
1324
1319
// If allTags is non-nil, matchFile records any encountered build tag
1325
1320
// 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 ) {
1327
1322
if strings .HasPrefix (name , "_" ) ||
1328
1323
strings .HasPrefix (name , "." ) {
1329
- return
1324
+ return nil , nil
1330
1325
}
1331
1326
1332
1327
i := strings .LastIndex (name , "." )
@@ -1336,55 +1331,53 @@ func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binary
1336
1331
ext := name [i :]
1337
1332
1338
1333
if ! ctxt .goodOSArchFile (name , allTags ) && ! ctxt .UseAllFiles {
1339
- return
1334
+ return nil , nil
1340
1335
}
1341
1336
1342
1337
if ext != ".go" && fileListForExt (& dummyPkg , ext ) == nil {
1343
1338
// skip
1344
- return
1339
+ return nil , nil
1345
1340
}
1346
1341
1342
+ info := & fileInfo {name : ctxt .joinPath (dir , name ), fset : fset }
1347
1343
if ext == ".syso" {
1348
1344
// binary, no reading
1349
- match = true
1350
- return
1345
+ return info , nil
1351
1346
}
1352
1347
1353
- filename = ctxt .joinPath (dir , name )
1354
- f , err := ctxt .openFile (filename )
1348
+ f , err := ctxt .openFile (info .name )
1355
1349
if err != nil {
1356
- return
1350
+ return nil , err
1357
1351
}
1358
1352
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" ) {
1362
1356
binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files
1363
1357
}
1364
1358
} else {
1365
1359
binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources
1366
- data , err = readComments (f )
1360
+ info . header , err = readComments (f )
1367
1361
}
1368
1362
f .Close ()
1369
1363
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 )
1372
1365
}
1373
1366
1374
1367
// 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 )
1376
1369
if err != nil {
1377
- return // non- nil err
1370
+ return nil , err
1378
1371
}
1379
1372
if ! ok && ! ctxt .UseAllFiles {
1380
- return // nil err
1373
+ return nil , nil
1381
1374
}
1382
1375
1383
1376
if binaryOnly != nil && sawBinaryOnly {
1384
1377
* binaryOnly = true
1385
1378
}
1386
- match = true
1387
- return
1379
+
1380
+ return info , nil
1388
1381
}
1389
1382
1390
1383
func cleanImports (m map [string ][]token.Position ) ([]string , map [string ][]token.Position ) {
0 commit comments