Skip to content

x/tools/gopls: suggest rand.N for time.Duration random generation #81323

Open

Description

@Amirali-Amirifar

gopls version

Build info

golang.org/x/tools/gopls v0.20.0
golang.org/x/tools/gopls@v0.20.0 h1:fxOYZXKl6IsOTKIh6IgjDbIDHlr5btOtOUkrGOgFDB4=
github.com/BurntSushi/toml@v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/fatih/camelcase@v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
github.com/fatih/gomodifytags@v1.17.1-0.20250423142747-f3939df9aa3c h1:dDSgAjoOMp8da3egfz0t2S+t8RGOpEmEXZubcGuc0Bg=
github.com/fatih/structtag@v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fsnotify/fsnotify@v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/google/go-cmp@v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
golang.org/x/exp/typeparams@v0.0.0-20250620022241-b7579e27df2b h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo=
golang.org/x/mod@v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/sync@v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sys@v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/telemetry@v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ=
golang.org/x/text@v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/tools@v0.35.1-0.20250728180453-01a3475a31bc h1:ZRKyKRJl/YEWl9ScZwd6Ua6xSt7DE6tHp1I3ucMroGM=
golang.org/x/vuln@v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
honnef.co/go/tools@v0.7.0-0.dev.0.20250523013057-bbc2f4dd71ea h1:fj8r9irJSpolAGUdZBxJIRY3lLc4jH2Dt4lwnWyWwpw=
mvdan.cc/gofumpt@v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k=
mvdan.cc/xurls/v2@v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
go: go1.25.0

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/amirali/go/bin'
GOCACHE='/Users/amirali/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/amirali/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT='jsonv2'
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/7j/t938qv7d49d134ywtsj94m9c0000gn/T/go-build2206170510=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='/Users/amirali/Projects/randfix/go.mod'
GOMODCACHE='/Users/amirali/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPACKAGESDRIVER=''
GOPATH='/Users/amirali/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/homebrew/Cellar/go/1.27.0/libexec'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/amirali/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/opt/homebrew/Cellar/go/1.27.0/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.27.0'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

I was refactoring some code which used old math/rand into newer math/rand/v2 which generated random time durations for testing. But after refactoring, we can leverage the rand.IntN generics and multiplying it by a time unit:

package main

import (
	"math/rand/v2"
	"time"
)

func main() {
	// Current pattern (clunky, requires casting)
	_ = time.Duration(rand.Int64N(int64(5 * time.Second)))

	// Modernized pattern
	_ = rand.N(5 * time.Second)
}

What did you see happen?

Nothing

What did you expect to see?

I expected the modernize analyzer (and by extension, gopls quick fixes) to suggest replacing the clunky pattern with the cleaner, idiomatic rand.N generic function, since time.Duration is an int64 under the hood and is fully supported by rand.N[T].
I got this idea from reading https://go.dev/blog/randv2 blog, a real use case can be viewed in this PR nats-io/nats-server#8557.

Editor and settings

No response

Logs

No response

Activity

  1. added
    goplsIssues related to the Go language server, gopls.
    ToolsThis label describes issues relating to any tools in the x/tools repository.
    on Sep 2, 2026
  2. added this to the Unreleased milestone on Sep 2, 2026
  3. gopherbot commented on Sep 3, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/826944 mentions this issue: go/analysis/passes/modernize: suggest rand.N for durations

  4. added
    FeatureRequestIssues asking for a new feature that does not need a proposal.
    on Sep 3, 2026
  5. adonovan commented on Sep 3, 2026

    @adonovan
    Member

    This seems like a reasonable idea; my only concern is that it it's a pretty obscure pattern than might not turn up many hits. If the diagnostic is very accurate and the fix very reliable, that still might be acceptable so long as the computation is cheap. That means the implementation should reject candidate packages as efficiently as possible, for example those that don't import both time and math/rand, without visiting syntax.

    @madelinekalil is going to run it over the corpus to see what it turns up.

  6. madelinekalil commented on Sep 8, 2026

    @madelinekalil
    Contributor

    I ran this analyzer pattern over ~30,000 modules from the module mirror corpus and it yielded 54 unique occurrences. Some examples:

    1. https://go-mod-viewer.appspot.com/github.com/qiniu/go-sdk/v7@v7.27.0/sandbox/sandbox.go#L248 "\t}\n\tjitter := time.Duration(rand.Int64N(int64(base/2 + 1)))\n\treturn base + jitter"
    2. https://go-mod-viewer.appspot.com/github.com/grafana/synthetic-monitoring-agent@v0.64.2/internal/k6runner/http.go#L171,
      "\t\t// Backoff linearly, adding some jitter.\n\t\twait += r.backoff + time.Duration(rand.Int64N(int64(r.backoff)))\n\t}"
    3. https://go-mod-viewer.appspot.com/github.com/anthropics/anthropic-sdk-go@v1.70.1/betasessiontoolrunner.go#L814,
      "\thalf := d / 2\n\treturn half + time.Duration(rand.Int64N(int64(d-half)))\n}"

    This pattern is uncommon, so I'm not yet sure whether we want to accept this. I'll take a look at the CL

  7. added
    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.
    on Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    FeatureRequestIssues asking for a new feature that does not need a proposal.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.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

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions