Skip to content

Commit 6aa28d3

Browse files
author
Jay Conrod
committed
go/build: report positions for go:embed directives
For #43469 For #43632 Change-Id: I9ac2da690344935da0e1dbe00b134dfcee65ec8a Reviewed-on: https://go-review.googlesource.com/c/go/+/283636 Run-TryBot: Jay Conrod <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Jay Conrod <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent 7eb31d9 commit 6aa28d3

File tree

4 files changed

+136
-66
lines changed

4 files changed

+136
-66
lines changed

api/go1.16.txt

+3
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,12 @@ pkg embed, type FS struct
226226
pkg flag, func Func(string, string, func(string) error)
227227
pkg flag, method (*FlagSet) Func(string, string, func(string) error)
228228
pkg go/build, type Package struct, EmbedPatterns []string
229+
pkg go/build, type Package struct, EmbedPatternPos map[string][]token.Position
229230
pkg go/build, type Package struct, IgnoredOtherFiles []string
230231
pkg go/build, type Package struct, TestEmbedPatterns []string
232+
pkg go/build, type Package struct, TestEmbedPatternPos map[string][]token.Position
231233
pkg go/build, type Package struct, XTestEmbedPatterns []string
234+
pkg go/build, type Package struct, XTestEmbedPatternPos map[string][]token.Position
232235
pkg html/template, func ParseFS(fs.FS, ...string) (*Template, error)
233236
pkg html/template, method (*Template) ParseFS(fs.FS, ...string) (*Template, error)
234237
pkg io, func NopCloser(Reader) ReadCloser

src/go/build/build.go

+40-28
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,12 @@ type Package struct {
449449
// //go:embed a* b.c
450450
// then the list will contain those two strings as separate entries.
451451
// (See package embed for more details about //go:embed.)
452-
EmbedPatterns []string // patterns from GoFiles, CgoFiles
453-
TestEmbedPatterns []string // patterns from TestGoFiles
454-
XTestEmbedPatterns []string // patterns from XTestGoFiles
452+
EmbedPatterns []string // patterns from GoFiles, CgoFiles
453+
EmbedPatternPos map[string][]token.Position // line information for EmbedPatterns
454+
TestEmbedPatterns []string // patterns from TestGoFiles
455+
TestEmbedPatternPos map[string][]token.Position // line information for TestEmbedPatterns
456+
XTestEmbedPatterns []string // patterns from XTestGoFiles
457+
XTestEmbedPatternPos map[string][]token.Position // line information for XTestEmbedPatternPos
455458
}
456459

457460
// IsCommand reports whether the package is considered a
@@ -794,10 +797,12 @@ Found:
794797
var badGoError error
795798
var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
796799
var firstFile, firstCommentFile string
797-
var embeds, testEmbeds, xTestEmbeds []string
798-
imported := make(map[string][]token.Position)
799-
testImported := make(map[string][]token.Position)
800-
xTestImported := make(map[string][]token.Position)
800+
embedPos := make(map[string][]token.Position)
801+
testEmbedPos := make(map[string][]token.Position)
802+
xTestEmbedPos := make(map[string][]token.Position)
803+
importPos := make(map[string][]token.Position)
804+
testImportPos := make(map[string][]token.Position)
805+
xTestImportPos := make(map[string][]token.Position)
801806
allTags := make(map[string]bool)
802807
fset := token.NewFileSet()
803808
for _, d := range dirs {
@@ -920,40 +925,42 @@ Found:
920925
}
921926
}
922927

923-
var fileList, embedList *[]string
924-
var importMap map[string][]token.Position
928+
var fileList *[]string
929+
var importMap, embedMap map[string][]token.Position
925930
switch {
926931
case isCgo:
927932
allTags["cgo"] = true
928933
if ctxt.CgoEnabled {
929934
fileList = &p.CgoFiles
930-
importMap = imported
931-
embedList = &embeds
935+
importMap = importPos
936+
embedMap = embedPos
932937
} else {
933-
// Ignore imports from cgo files if cgo is disabled.
938+
// Ignore imports and embeds from cgo files if cgo is disabled.
934939
fileList = &p.IgnoredGoFiles
935940
}
936941
case isXTest:
937942
fileList = &p.XTestGoFiles
938-
importMap = xTestImported
939-
embedList = &xTestEmbeds
943+
importMap = xTestImportPos
944+
embedMap = xTestEmbedPos
940945
case isTest:
941946
fileList = &p.TestGoFiles
942-
importMap = testImported
943-
embedList = &testEmbeds
947+
importMap = testImportPos
948+
embedMap = testEmbedPos
944949
default:
945950
fileList = &p.GoFiles
946-
importMap = imported
947-
embedList = &embeds
951+
importMap = importPos
952+
embedMap = embedPos
948953
}
949954
*fileList = append(*fileList, name)
950955
if importMap != nil {
951956
for _, imp := range info.imports {
952957
importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
953958
}
954959
}
955-
if embedList != nil {
956-
*embedList = append(*embedList, info.embeds...)
960+
if embedMap != nil {
961+
for _, emb := range info.embeds {
962+
embedMap[emb.pattern] = append(embedMap[emb.pattern], emb.pos)
963+
}
957964
}
958965
}
959966

@@ -962,13 +969,13 @@ Found:
962969
}
963970
sort.Strings(p.AllTags)
964971

965-
p.EmbedPatterns = uniq(embeds)
966-
p.TestEmbedPatterns = uniq(testEmbeds)
967-
p.XTestEmbedPatterns = uniq(xTestEmbeds)
972+
p.EmbedPatterns, p.EmbedPatternPos = cleanDecls(embedPos)
973+
p.TestEmbedPatterns, p.TestEmbedPatternPos = cleanDecls(testEmbedPos)
974+
p.XTestEmbedPatterns, p.XTestEmbedPatternPos = cleanDecls(xTestEmbedPos)
968975

969-
p.Imports, p.ImportPos = cleanImports(imported)
970-
p.TestImports, p.TestImportPos = cleanImports(testImported)
971-
p.XTestImports, p.XTestImportPos = cleanImports(xTestImported)
976+
p.Imports, p.ImportPos = cleanDecls(importPos)
977+
p.TestImports, p.TestImportPos = cleanDecls(testImportPos)
978+
p.XTestImports, p.XTestImportPos = cleanDecls(xTestImportPos)
972979

973980
// add the .S/.sx files only if we are using cgo
974981
// (which means gcc will compile them).
@@ -1340,7 +1347,7 @@ type fileInfo struct {
13401347
parsed *ast.File
13411348
parseErr error
13421349
imports []fileImport
1343-
embeds []string
1350+
embeds []fileEmbed
13441351
embedErr error
13451352
}
13461353

@@ -1350,6 +1357,11 @@ type fileImport struct {
13501357
doc *ast.CommentGroup
13511358
}
13521359

1360+
type fileEmbed struct {
1361+
pattern string
1362+
pos token.Position
1363+
}
1364+
13531365
// matchFile determines whether the file with the given name in the given directory
13541366
// should be included in the package being constructed.
13551367
// If the file should be included, matchFile returns a non-nil *fileInfo (and a nil error).
@@ -1424,7 +1436,7 @@ func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binary
14241436
return info, nil
14251437
}
14261438

1427-
func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
1439+
func cleanDecls(m map[string][]token.Position) ([]string, map[string][]token.Position) {
14281440
all := make([]string, 0, len(m))
14291441
for path := range m {
14301442
all = append(all, path)

src/go/build/read.go

+55-19
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fmt"
1111
"go/ast"
1212
"go/parser"
13+
"go/token"
1314
"io"
1415
"strconv"
1516
"strings"
@@ -24,6 +25,18 @@ type importReader struct {
2425
err error
2526
eof bool
2627
nerr int
28+
pos token.Position
29+
}
30+
31+
func newImportReader(name string, r io.Reader) *importReader {
32+
return &importReader{
33+
b: bufio.NewReader(r),
34+
pos: token.Position{
35+
Filename: name,
36+
Line: 1,
37+
Column: 1,
38+
},
39+
}
2740
}
2841

2942
func isIdent(c byte) bool {
@@ -66,22 +79,32 @@ func (r *importReader) readByte() byte {
6679
// readByteNoBuf is like readByte but doesn't buffer the byte.
6780
// It exhausts r.buf before reading from r.b.
6881
func (r *importReader) readByteNoBuf() byte {
82+
var c byte
83+
var err error
6984
if len(r.buf) > 0 {
70-
c := r.buf[0]
85+
c = r.buf[0]
7186
r.buf = r.buf[1:]
72-
return c
73-
}
74-
c, err := r.b.ReadByte()
75-
if err == nil && c == 0 {
76-
err = errNUL
87+
} else {
88+
c, err = r.b.ReadByte()
89+
if err == nil && c == 0 {
90+
err = errNUL
91+
}
7792
}
93+
7894
if err != nil {
7995
if err == io.EOF {
8096
r.eof = true
8197
} else if r.err == nil {
8298
r.err = err
8399
}
84-
c = 0
100+
return 0
101+
}
102+
r.pos.Offset++
103+
if c == '\n' {
104+
r.pos.Line++
105+
r.pos.Column = 1
106+
} else {
107+
r.pos.Column++
85108
}
86109
return c
87110
}
@@ -323,7 +346,7 @@ func (r *importReader) readImport() {
323346
// readComments is like io.ReadAll, except that it only reads the leading
324347
// block of comments in the file.
325348
func readComments(f io.Reader) ([]byte, error) {
326-
r := &importReader{b: bufio.NewReader(f)}
349+
r := newImportReader("", f)
327350
r.peekByte(true)
328351
if r.err == nil && !r.eof {
329352
// Didn't reach EOF, so must have found a non-space byte. Remove it.
@@ -340,7 +363,7 @@ func readComments(f io.Reader) ([]byte, error) {
340363
// It only returns an error if there are problems reading the file,
341364
// not for syntax errors in the file itself.
342365
func readGoInfo(f io.Reader, info *fileInfo) error {
343-
r := &importReader{b: bufio.NewReader(f)}
366+
r := newImportReader(info.name, f)
344367

345368
r.readKeyword("package")
346369
r.readIdent()
@@ -428,6 +451,7 @@ func readGoInfo(f io.Reader, info *fileInfo) error {
428451
var line []byte
429452
for first := true; r.findEmbed(first); first = false {
430453
line = line[:0]
454+
pos := r.pos
431455
for {
432456
c := r.readByteNoBuf()
433457
if c == '\n' || r.err != nil || r.eof {
@@ -438,9 +462,9 @@ func readGoInfo(f io.Reader, info *fileInfo) error {
438462
// Add args if line is well-formed.
439463
// Ignore badly-formed lines - the compiler will report them when it finds them,
440464
// and we can pretend they are not there to help go list succeed with what it knows.
441-
args, err := parseGoEmbed(string(line))
465+
embs, err := parseGoEmbed(string(line), pos)
442466
if err == nil {
443-
info.embeds = append(info.embeds, args...)
467+
info.embeds = append(info.embeds, embs...)
444468
}
445469
}
446470
}
@@ -450,11 +474,23 @@ func readGoInfo(f io.Reader, info *fileInfo) error {
450474

451475
// parseGoEmbed parses the text following "//go:embed" to extract the glob patterns.
452476
// It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings.
453-
// There is a copy of this code in cmd/compile/internal/gc/noder.go as well.
454-
func parseGoEmbed(args string) ([]string, error) {
455-
var list []string
456-
for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) {
477+
// This is based on a similar function in cmd/compile/internal/gc/noder.go;
478+
// this version calculates position information as well.
479+
func parseGoEmbed(args string, pos token.Position) ([]fileEmbed, error) {
480+
trimBytes := func(n int) {
481+
pos.Offset += n
482+
pos.Column += utf8.RuneCountInString(args[:n])
483+
args = args[n:]
484+
}
485+
trimSpace := func() {
486+
trim := strings.TrimLeftFunc(args, unicode.IsSpace)
487+
trimBytes(len(args) - len(trim))
488+
}
489+
490+
var list []fileEmbed
491+
for trimSpace(); args != ""; trimSpace() {
457492
var path string
493+
pathPos := pos
458494
Switch:
459495
switch args[0] {
460496
default:
@@ -466,15 +502,15 @@ func parseGoEmbed(args string) ([]string, error) {
466502
}
467503
}
468504
path = args[:i]
469-
args = args[i:]
505+
trimBytes(i)
470506

471507
case '`':
472508
i := strings.Index(args[1:], "`")
473509
if i < 0 {
474510
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
475511
}
476512
path = args[1 : 1+i]
477-
args = args[1+i+1:]
513+
trimBytes(1 + i + 1)
478514

479515
case '"':
480516
i := 1
@@ -489,7 +525,7 @@ func parseGoEmbed(args string) ([]string, error) {
489525
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1])
490526
}
491527
path = q
492-
args = args[i+1:]
528+
trimBytes(i + 1)
493529
break Switch
494530
}
495531
}
@@ -504,7 +540,7 @@ func parseGoEmbed(args string) ([]string, error) {
504540
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
505541
}
506542
}
507-
list = append(list, path)
543+
list = append(list, fileEmbed{path, pathPos})
508544
}
509545
return list, nil
510546
}

0 commit comments

Comments
 (0)