From d1f873e3c1b2cf7231a30697aea158ae6cfdbb5f Mon Sep 17 00:00:00 2001 From: James Hartig Date: Fri, 19 Mar 2021 15:24:42 -0400 Subject: [PATCH] modfile: fix Cleanup clobbering Line reference Fixes golang/go#45130 Change-Id: I2dccba5e958911177f10a5104a182f86ff8378d9 Reviewed-on: https://go-review.googlesource.com/c/mod/+/303234 Reviewed-by: Michael Matloob LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase --- modfile/read.go | 7 ++- modfile/read_test.go | 131 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 3 deletions(-) diff --git a/modfile/read.go b/modfile/read.go index 2205682..de1b982 100644 --- a/modfile/read.go +++ b/modfile/read.go @@ -226,8 +226,9 @@ func (x *FileSyntax) Cleanup() { continue } if ww == 1 && len(stmt.RParen.Comments.Before) == 0 { - // Collapse block into single line. - line := &Line{ + // Collapse block into single line but keep the Line reference used by the + // parsed File structure. + *stmt.Line[0] = Line{ Comments: Comments{ Before: commentsAdd(stmt.Before, stmt.Line[0].Before), Suffix: commentsAdd(stmt.Line[0].Suffix, stmt.Suffix), @@ -235,7 +236,7 @@ func (x *FileSyntax) Cleanup() { }, Token: stringsAdd(stmt.Token, stmt.Line[0].Token), } - x.Stmt[w] = line + x.Stmt[w] = stmt.Line[0] w++ continue } diff --git a/modfile/read_test.go b/modfile/read_test.go index efc75e1..8f17eea 100644 --- a/modfile/read_test.go +++ b/modfile/read_test.go @@ -603,3 +603,134 @@ comments before "// k" }) } } + +func TestCleanup(t *testing.T) { + for _, test := range []struct { + desc string + want string + input []Expr + }{ + { + desc: "simple_lines", + want: `line: module a +line: require b v1.0.0 +`, + input: []Expr{ + &Line{ + Token: []string{"module", "a"}, + }, + &Line{ + Token: []string{"require", "b", "v1.0.0"}, + }, + &Line{ + Token: nil, + }, + }, + }, { + desc: "line_block", + want: `line: module a +block: require +blockline: b v1.0.0 +blockline: c v1.0.0 +`, + input: []Expr{ + &Line{ + Token: []string{"module", "a"}, + }, + &LineBlock{ + Token: []string{"require"}, + Line: []*Line{ + { + Token: []string{"b", "v1.0.0"}, + InBlock: true, + }, + { + Token: nil, + InBlock: true, + }, + { + Token: []string{"c", "v1.0.0"}, + InBlock: true, + }, + }, + }, + }, + }, { + desc: "collapse", + want: `line: module a +line: require b v1.0.0 +`, + input: []Expr{ + &Line{ + Token: []string{"module", "a"}, + }, + &LineBlock{ + Token: []string{"require"}, + Line: []*Line{ + { + Token: []string{"b", "v1.0.0"}, + InBlock: true, + }, + { + Token: nil, + InBlock: true, + }, + }, + }, + }, + }, + } { + t.Run(test.desc, func(t *testing.T) { + syntax := &FileSyntax{ + Stmt: test.input, + } + syntax.Cleanup() + + buf := &bytes.Buffer{} + for _, stmt := range syntax.Stmt { + switch stmt := stmt.(type) { + case *Line: + fmt.Fprintf(buf, "line: %v\n", strings.Join(stmt.Token, " ")) + case *LineBlock: + fmt.Fprintf(buf, "block: %v\n", strings.Join(stmt.Token, " ")) + for _, line := range stmt.Line { + fmt.Fprintf(buf, "blockline: %v\n", strings.Join(line.Token, " ")) + } + } + } + + got := strings.TrimSpace(buf.String()) + want := strings.TrimSpace(test.want) + if got != want { + t.Errorf("got:\n%s\nwant:\n%s", got, want) + } + }) + } +} + +// Issue 45130: File.Cleanup breaks references so future edits do nothing +func TestCleanupMaintainsRefs(t *testing.T) { + lineB := &Line{ + Token: []string{"b", "v1.0.0"}, + InBlock: true, + } + syntax := &FileSyntax{ + Stmt: []Expr{ + &LineBlock{ + Token: []string{"require"}, + Line: []*Line{ + lineB, + { + Token: nil, + InBlock: true, + }, + }, + }, + }, + } + syntax.Cleanup() + + if syntax.Stmt[0] != lineB { + t.Errorf("got:\n%v\nwant:\n%v", syntax.Stmt[0], lineB) + } +}