Skip to content

x/tools/gopls/internal/analysis/modernize: stringsbuilder fix deletes GenDecl's rparen #75318

@cuishuang

Description

@cuishuang

gopls version

binary compiled by latest code

go env

AR='ar'
CC='cc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='c++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN='/Users/mac/go/bin'
GOCACHE='/Users/mac/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/mac/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/tq/m955dwkd1519phkp2hwpv9_80000gn/T/go-build2400307511=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/Users/mac/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/mac/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/mac/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.24.3'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

package main

import (
	"fmt"
)

type Keeper struct{}

type Context struct{}

type FruitPrice struct {
	Id       int
	Current  int // Current price
	Expected int // Expected price
}

func (k Keeper) GetFruitPrices(ctx Context) []FruitPrice {
	// Example fruit prices
	return []FruitPrice{
		{Id: 1, Current: 50, Expected: 60},
		{Id: 2, Current: 80, Expected: 70},
	}
}

func PriceInvariant(k Keeper) func(ctx Context) (string, bool) {
	return func(ctx Context) (string, bool) {
		var (
			broken bool
			msg    string
		)

		for _, price := range k.GetFruitPrices(ctx) {
			if price.Current > price.Expected {
				msg += fmt.Sprintf("Current price > expected price for fruit %d\n", price.Id)
				broken = true
			}
		}

		return msg, broken
	}
}

func main() {
	k := Keeper{}
	ctx := Context{}
	invariant := PriceInvariant(k)

	msg, broken := invariant(ctx)
	if broken {
		fmt.Println("Invariant broken:", msg)
	} else {
		fmt.Println("Invariant holds")
	}
}

The Output:

Invariant broken: Current price > expected price for fruit 2

What did you see happen?

After executing modernize -fix -test ./..., it will become.

package main

import (
	"strings"
	"fmt"
)

type Keeper struct{}

type Context struct{}

type FruitPrice struct {
	Id       int
	Current  int // Current price
	Expected int // Expected price
}

func (k Keeper) GetFruitPrices(ctx Context) []FruitPrice {
	// Example fruit prices
	return []FruitPrice{
		{Id: 1, Current: 50, Expected: 60},
		{Id: 2, Current: 80, Expected: 70},
	}
}

func PriceInvariant(k Keeper) func(ctx Context) (string, bool) {
	return func(ctx Context) (string, bool) {
		var (
			broken bool
			msg strings.Builder

		for _, price := range k.GetFruitPrices(ctx) {
			if price.Current > price.Expected {
				msg .WriteString(fmt.Sprintf("Current price > expected price for fruit %d\n", price.Id))
				broken = true
			}
		}

		return msg.String(), broken
	}
}

func main() {
	k := Keeper{}
	ctx := Context{}
	invariant := PriceInvariant(k)

	msg, broken := invariant(ctx)
	if broken {
		fmt.Println("Invariant broken:", msg)
	} else {
		fmt.Println("Invariant holds")
	}
}

Output:

# command-line-arguments
./main.go:32:3: syntax error: unexpected keyword for, expected name
./main.go:41:1: syntax error: non-declaration statement outside function body

What did you expect to see?

package main

import (
	"fmt"
	"strings"
)

type Keeper struct{}

type Context struct{}

type FruitPrice struct {
	Id       int
	Current  int // Current price
	Expected int // Expected price
}

func (k Keeper) GetFruitPrices(ctx Context) []FruitPrice {
	// Example fruit prices
	return []FruitPrice{
		{Id: 1, Current: 50, Expected: 60},
		{Id: 2, Current: 80, Expected: 70},
	}
}

func PriceInvariant(k Keeper) func(ctx Context) (string, bool) {
	return func(ctx Context) (string, bool) {
		var (
			broken bool
			msg    strings.Builder
		)

		for _, price := range k.GetFruitPrices(ctx) {
			if price.Current > price.Expected {
				msg.WriteString(fmt.Sprintf("Current price > expected price for fruit %d\n", price.Id))
				broken = true
			}
		}

		return msg.String(), broken
	}
}

func main() {
	k := Keeper{}
	ctx := Context{}
	invariant := PriceInvariant(k)

	msg, broken := invariant(ctx)
	if broken {
		fmt.Println("Invariant broken:", msg)
	} else {
		fmt.Println("Invariant holds")
	}
}

Editor and settings

No response

Logs

No response

Metadata

Metadata

Assignees

Labels

ToolsThis label describes issues relating to any tools in the x/tools repository.goplsIssues related to the Go language server, gopls.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions