diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go index a295a68d6f8417..28e008d4398b2a 100644 --- a/src/go/printer/nodes.go +++ b/src/go/printer/nodes.go @@ -1156,6 +1156,14 @@ func (p *printer) possibleSelectorExpr(expr ast.Expr, prec1, depth int) bool { // multiple lines. func (p *printer) selectorExpr(x *ast.SelectorExpr, depth int, isMethod bool) bool { p.expr1(x.X, token.HighestPrec, depth) + + // We don't have the position of the dot, so we have to predict it, + // to avoid issues with comment handling. + // See https://go.dev/issue/70978 and TestIssue70978 for more details. + if x.Sel.Pos().IsValid() && p.pos.Offset > p.posFor(x.Sel.Pos()).Offset { + p.setPos(x.Sel.Pos()) + } + p.print(token.PERIOD) if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line { p.print(indent, newline) diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go index 2a9c8be3003249..bde0089a245d43 100644 --- a/src/go/printer/printer_test.go +++ b/src/go/printer/printer_test.go @@ -16,6 +16,7 @@ import ( "io" "os" "path/filepath" + "strings" "testing" "time" ) @@ -863,3 +864,77 @@ func TestEmptyDecl(t *testing.T) { // issue 63566 } } } + +func TestIssue70978(t *testing.T) { + cases := []struct { + src string + want string + newName string + }{ + { + newName: "someotherfmtpackage", + src: `package main + +func main() { + // comment + + fmt.Println() // Comment +} +`, + want: `package main + +func main() { + // comment + + someotherfmtpackage.Println() // Comment +} +`, + }, + { + newName: "someotherfmtpkg", + src: `package main + +func main() { + // comment + + fmt.Println() // Comment +} +`, + want: `package main + +func main() { + // comment + + someotherfmtpkg.Println() // Comment +} +`, + }, + } + + for _, tt := range cases { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "test.go", tt.src, parser.SkipObjectResolution|parser.ParseComments) + if err != nil { + t.Fatal(err) + } + + ast.Inspect(f, func(n ast.Node) bool { + switch n := n.(type) { + case *ast.SelectorExpr: + switch x := n.X.(type) { + case *ast.Ident: + x.Name = tt.newName + } + } + return true + }) + + var b strings.Builder + config := Config{Mode: UseSpaces | TabIndent, Tabwidth: 8} + config.Fprint(&b, fset, f) + got := b.String() + if got != tt.want { + t.Errorf("unexpected Fprint output:\n%s\nwant:\n%s", got, tt.want) + } + } +}