mirror of https://github.com/golang/go.git
cmd/cover: avoid repeating positions
When using //line directives and unformatted code it is possible for positions to repeat. Increment the final column position to avoid that. Fixes #27350 Change-Id: I2faccc31360075e9814d4a024b0f98b117f8ce97 Reviewed-on: https://go-review.googlesource.com/c/153061 Run-TryBot: Rob Pike <r@golang.org> Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
77caea5bf2
commit
d689946302
|
|
@ -646,9 +646,21 @@ func (f *File) addVariables(w io.Writer) {
|
||||||
// - 32-bit starting line number
|
// - 32-bit starting line number
|
||||||
// - 32-bit ending line number
|
// - 32-bit ending line number
|
||||||
// - (16 bit ending column number << 16) | (16-bit starting column number).
|
// - (16 bit ending column number << 16) | (16-bit starting column number).
|
||||||
|
var lastStart, lastEnd token.Position
|
||||||
for i, block := range f.blocks {
|
for i, block := range f.blocks {
|
||||||
start := f.fset.Position(block.startByte)
|
start := f.fset.Position(block.startByte)
|
||||||
end := f.fset.Position(block.endByte)
|
end := f.fset.Position(block.endByte)
|
||||||
|
|
||||||
|
// It is possible for positions to repeat when there is a
|
||||||
|
// line directive that does not specify column information
|
||||||
|
// and the input has not been passed through gofmt.
|
||||||
|
// See issue #27350 and TestHtmlUnformatted.
|
||||||
|
if samePos(start, lastStart) && samePos(end, lastEnd) {
|
||||||
|
end.Column++
|
||||||
|
}
|
||||||
|
lastStart = start
|
||||||
|
lastEnd = end
|
||||||
|
|
||||||
fmt.Fprintf(w, "\t\t%d, %d, %#x, // [%d]\n", start.Line, end.Line, (end.Column&0xFFFF)<<16|(start.Column&0xFFFF), i)
|
fmt.Fprintf(w, "\t\t%d, %d, %#x, // [%d]\n", start.Line, end.Line, (end.Column&0xFFFF)<<16|(start.Column&0xFFFF), i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -697,3 +709,11 @@ func isValidIdentifier(ident string) bool {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// samePos returns whether two positions have the same file/line/column.
|
||||||
|
// We don't use p1 == p2 because token.Position also has an Offset field,
|
||||||
|
// and when the input uses //line directives two Positions can have different
|
||||||
|
// Offset values while having the same file/line/dolumn.
|
||||||
|
func samePos(p1, p2 token.Position) bool {
|
||||||
|
return p1.Filename == p2.Filename && p1.Line == p2.Line && p1.Column == p2.Column
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,16 @@ var (
|
||||||
htmlGolden = filepath.Join(testdata, "html", "html.golden")
|
htmlGolden = filepath.Join(testdata, "html", "html.golden")
|
||||||
|
|
||||||
// Temporary files.
|
// Temporary files.
|
||||||
tmpTestMain string
|
tmpTestMain string
|
||||||
coverInput string
|
coverInput string
|
||||||
coverOutput string
|
coverOutput string
|
||||||
htmlProfile string
|
htmlProfile string
|
||||||
htmlHTML string
|
htmlHTML string
|
||||||
|
htmlUDir string
|
||||||
|
htmlU string
|
||||||
|
htmlUTest string
|
||||||
|
htmlUProfile string
|
||||||
|
htmlUHTML string
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -85,6 +90,11 @@ func TestMain(m *testing.M) {
|
||||||
coverOutput = filepath.Join(dir, "test_cover.go")
|
coverOutput = filepath.Join(dir, "test_cover.go")
|
||||||
htmlProfile = filepath.Join(dir, "html.cov")
|
htmlProfile = filepath.Join(dir, "html.cov")
|
||||||
htmlHTML = filepath.Join(dir, "html.html")
|
htmlHTML = filepath.Join(dir, "html.html")
|
||||||
|
htmlUDir = filepath.Join(dir, "htmlunformatted")
|
||||||
|
htmlU = filepath.Join(htmlUDir, "htmlunformatted.go")
|
||||||
|
htmlUTest = filepath.Join(htmlUDir, "htmlunformatted_test.go")
|
||||||
|
htmlUProfile = filepath.Join(htmlUDir, "htmlunformatted.cov")
|
||||||
|
htmlUHTML = filepath.Join(htmlUDir, "htmlunformatted.html")
|
||||||
|
|
||||||
status := m.Run()
|
status := m.Run()
|
||||||
|
|
||||||
|
|
@ -427,12 +437,54 @@ func TestCoverHTML(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test HTML processing with a source file not run through gofmt.
|
||||||
|
// Issue #27350.
|
||||||
|
func TestHtmlUnformatted(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testenv.MustHaveGoRun(t)
|
||||||
|
buildCover(t)
|
||||||
|
|
||||||
|
if err := os.Mkdir(htmlUDir, 0777); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const htmlUContents = `
|
||||||
|
package htmlunformatted
|
||||||
|
|
||||||
|
var g int
|
||||||
|
|
||||||
|
func F() {
|
||||||
|
//line x.go:1
|
||||||
|
{ { F(); goto lab } }
|
||||||
|
lab:
|
||||||
|
}`
|
||||||
|
|
||||||
|
const htmlUTestContents = `package htmlunformatted`
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(htmlU, []byte(htmlUContents), 0444); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(htmlUTest, []byte(htmlUTestContents), 0444); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// go test -covermode=count -coverprofile TMPDIR/htmlunformatted.cov
|
||||||
|
cmd := exec.Command(testenv.GoToolPath(t), "test", toolexecArg, "-covermode=count", "-coverprofile", htmlUProfile)
|
||||||
|
cmd.Dir = htmlUDir
|
||||||
|
run(cmd, t)
|
||||||
|
|
||||||
|
// testcover -html TMPDIR/htmlunformatted.cov -o unformatted.html
|
||||||
|
cmd = exec.Command(testcover, "-html", htmlUProfile, "-o", htmlUHTML)
|
||||||
|
run(cmd, t)
|
||||||
|
}
|
||||||
|
|
||||||
func run(c *exec.Cmd, t *testing.T) {
|
func run(c *exec.Cmd, t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
t.Log("running", c.Args)
|
t.Log("running", c.Args)
|
||||||
c.Stdout = os.Stdout
|
out, err := c.CombinedOutput()
|
||||||
c.Stderr = os.Stderr
|
if len(out) > 0 {
|
||||||
err := c.Run()
|
t.Logf("%s", out)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue