all: use Go 1.26 things, run most gofix modernizers

I omitted a lot of the min/max modernizers because they didn't
result in more clear code.

Some of it's older "for x := range 123".

Also: errors.AsType, any, fmt.Appendf, etc.

Updates #18682

Change-Id: I83a451577f33877f962766a5b65ce86f7696471c
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2026-03-05 21:13:57 +00:00
committed by Brad Fitzpatrick
parent 4453cc5f53
commit bd2a2d53d3
168 changed files with 431 additions and 618 deletions
+5 -2
View File
@@ -69,8 +69,11 @@ type Opts struct {
// IsRetryableError returns true if the given error is retryable
// See [controlclient.apiResponseError]. Potentially retryable errors implement the Retryable() method.
func IsRetryableError(err error) bool {
var retryable interface{ Retryable() bool }
return errors.As(err, &retryable) && retryable.Retryable()
retryable, ok := errors.AsType[interface {
error
Retryable() bool
}](err)
return ok && retryable.Retryable()
}
type backoffOpts struct {
+1 -1
View File
@@ -15,7 +15,7 @@ func init() {
func breakTCPConnsLinux() error {
var matched int
for fd := 0; fd < 1000; fd++ {
for fd := range 1000 {
_, err := unix.GetsockoptTCPInfo(fd, unix.IPPROTO_TCP, unix.TCP_INFO)
if err == nil {
matched++
+3 -4
View File
@@ -36,9 +36,8 @@ func TestIsNotableNotify(t *testing.T) {
// We use reflect to catch fields that might be added in the future without
// remembering to update the [isNotableNotify] function.
rt := reflect.TypeFor[ipn.Notify]()
for i := range rt.NumField() {
for sf := range rt.Fields() {
n := &ipn.Notify{}
sf := rt.Field(i)
switch sf.Name {
case "_", "NetMap", "Engine", "Version":
// Already covered above or not applicable.
@@ -46,7 +45,7 @@ func TestIsNotableNotify(t *testing.T) {
case "DriveShares":
n.DriveShares = views.SliceOfViews[*drive.Share, drive.ShareView](make([]*drive.Share, 1))
default:
rf := reflect.ValueOf(n).Elem().Field(i)
rf := reflect.ValueOf(n).Elem().FieldByIndex(sf.Index)
switch rf.Kind() {
case reflect.Pointer:
rf.Set(reflect.New(rf.Type().Elem()))
@@ -64,7 +63,7 @@ func TestIsNotableNotify(t *testing.T) {
notify *ipn.Notify
want bool
}{
name: "field-" + rt.Field(i).Name,
name: "field-" + sf.Name,
notify: n,
want: true,
})
+1 -1
View File
@@ -339,7 +339,7 @@ func (h *ExtensionHost) FindMatchingExtension(target any) bool {
val := reflect.ValueOf(target)
typ := val.Type()
if typ.Kind() != reflect.Ptr || val.IsNil() {
if typ.Kind() != reflect.Pointer || val.IsNil() {
panic("ipnext: target must be a non-nil pointer")
}
targetType := typ.Elem()
+2 -3
View File
@@ -1010,9 +1010,8 @@ func TestNilExtensionHostMethodCall(t *testing.T) {
t.Parallel()
var h *ExtensionHost
typ := reflect.TypeOf(h)
for i := range typ.NumMethod() {
m := typ.Method(i)
typ := reflect.TypeFor[*ExtensionHost]()
for m := range typ.Methods() {
if strings.HasSuffix(m.Name, "ForTest") {
// Skip methods that are only for testing.
continue
+3 -10
View File
@@ -3687,12 +3687,7 @@ func generateInterceptTCPPortFunc(ports []uint16) func(uint16) bool {
f = func(p uint16) bool { return m[p] }
} else {
f = func(p uint16) bool {
for _, x := range ports {
if p == x {
return true
}
}
return false
return slices.Contains(ports, p)
}
}
}
@@ -7387,10 +7382,8 @@ var (
// allowedAutoRoute determines if the route being added via AdvertiseRoute (the app connector featuge) should be allowed.
func allowedAutoRoute(ipp netip.Prefix) bool {
// Note: blocking the addrs for globals, not solely the prefixes.
for _, addr := range disallowedAddrs {
if ipp.Addr() == addr {
return false
}
if slices.Contains(disallowedAddrs, ipp.Addr()) {
return false
}
for _, pfx := range disallowedRanges {
if pfx.Overlaps(ipp) {
+1 -1
View File
@@ -275,7 +275,7 @@ var skippedMapFields = []string{
func checkFieldCoverage(t *testing.T, nm *netmap.NetworkMap) {
t.Helper()
mt := reflect.TypeOf(nm).Elem()
mt := reflect.TypeFor[netmap.NetworkMap]()
mv := reflect.ValueOf(nm).Elem()
for i := 0; i < mt.NumField(); i++ {
f := mt.Field(i)
+1 -1
View File
@@ -103,7 +103,7 @@ func (s *peerAPIServer) listen(ip netip.Addr, tunIfIndex int) (ln net.Listener,
// deterministic that people will bake this into clients.
// We try a few times just in case something's already
// listening on that port (on all interfaces, probably).
for try := uint8(0); try < 5; try++ {
for try := range uint8(5) {
a16 := ip.As16()
hashData := a16[len(a16)-3:]
hashData[0] += try
+2 -2
View File
@@ -835,8 +835,8 @@ func (b *LocalBackend) proxyHandlerForBackend(backend string) (http.Handler, err
targetURL, insecure := expandProxyArg(backend)
// Handle unix: scheme specially
if strings.HasPrefix(targetURL, "unix:") {
socketPath := strings.TrimPrefix(targetURL, "unix:")
if after, ok := strings.CutPrefix(targetURL, "unix:"); ok {
socketPath := after
if socketPath == "" {
return nil, fmt.Errorf("empty unix socket path")
}
+3 -3
View File
@@ -101,9 +101,9 @@ func (b *LocalBackend) getSSHUsernames(req *tailcfg.C2NSSHUsernamesRequest) (*ta
mem.HasSuffix(mem.B(line), mem.S("/false")) {
continue
}
colon := bytes.IndexByte(line, ':')
if colon != -1 {
add(string(line[:colon]))
before, _, ok := bytes.Cut(line, []byte{':'})
if ok {
add(string(before))
}
}
}
+2 -5
View File
@@ -142,14 +142,11 @@ func (h *Handler) serveDebugDialTypes(w http.ResponseWriter, r *http.Request) {
var wg sync.WaitGroup
for _, dialer := range dialers {
dialer := dialer // loop capture
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
conn, err := dialer.dial(ctx, network, addr)
results <- result{dialer.name, conn, err}
}()
})
}
wg.Wait()
+6 -14
View File
@@ -439,12 +439,11 @@ func applyPrefsEdits(src, dst reflect.Value, mask map[string]reflect.Value) {
func maskFields(v reflect.Value) map[string]reflect.Value {
mask := make(map[string]reflect.Value)
for i := range v.NumField() {
f := v.Type().Field(i).Name
if !strings.HasSuffix(f, "Set") {
for sf, fv := range v.Fields() {
if !strings.HasSuffix(sf.Name, "Set") {
continue
}
mask[strings.TrimSuffix(f, "Set")] = v.Field(i)
mask[strings.TrimSuffix(sf.Name, "Set")] = fv
}
return mask
}
@@ -845,22 +844,15 @@ func (p *Prefs) SetAdvertiseExitNode(runExit bool) {
// Tailscale IP.
func peerWithTailscaleIP(st *ipnstate.Status, ip netip.Addr) (ps *ipnstate.PeerStatus, ok bool) {
for _, ps := range st.Peer {
for _, ip2 := range ps.TailscaleIPs {
if ip == ip2 {
return ps, true
}
if slices.Contains(ps.TailscaleIPs, ip) {
return ps, true
}
}
return nil, false
}
func isRemoteIP(st *ipnstate.Status, ip netip.Addr) bool {
for _, selfIP := range st.TailscaleIPs {
if ip == selfIP {
return false
}
}
return true
return !slices.Contains(st.TailscaleIPs, ip)
}
// ClearExitNode sets the ExitNodeID and ExitNodeIP to their zero values.
+2 -2
View File
@@ -27,8 +27,8 @@ import (
)
func fieldsOf(t reflect.Type) (fields []string) {
for i := range t.NumField() {
fields = append(fields, t.Field(i).Name)
for field := range t.Fields() {
fields = append(fields, field.Name)
}
return
}
+1 -1
View File
@@ -673,7 +673,7 @@ func CheckFunnelPort(wantedPort uint16, node *ipnstate.PeerStatus) error {
return deny("")
}
wantedPortString := strconv.Itoa(int(wantedPort))
for _, ps := range strings.Split(portsStr, ",") {
for ps := range strings.SplitSeq(portsStr, ",") {
if ps == "" {
continue
}
+1 -2
View File
@@ -189,8 +189,7 @@ func (s *awsStore) LoadState() error {
)
if err != nil {
var pnf *ssmTypes.ParameterNotFound
if errors.As(err, &pnf) {
if _, ok := errors.AsType[*ssmTypes.ParameterNotFound](err); ok {
// Create the parameter as it does not exist yet
// and return directly as it is defacto empty
return s.persistState()