Browse Source

all: use reflect.TypeFor now available in Go 1.22 (#11078)

Updates #cleanup

Signed-off-by: Joe Tsai <[email protected]>
Joe Tsai 2 years ago
parent
commit
94a4f701c2

+ 1 - 1
cmd/tailscale/cli/cli_test.go

@@ -802,7 +802,7 @@ func TestPrefFlagMapping(t *testing.T) {
 		}
 	}
 
-	prefType := reflect.TypeOf(ipn.Prefs{})
+	prefType := reflect.TypeFor[ipn.Prefs]()
 	for i := 0; i < prefType.NumField(); i++ {
 		prefName := prefType.Field(i).Name
 		if prefHasFlag[prefName] {

+ 1 - 1
cmd/tailscale/cli/up.go

@@ -726,7 +726,7 @@ func init() {
 
 func addPrefFlagMapping(flagName string, prefNames ...string) {
 	prefsOfFlag[flagName] = prefNames
-	prefType := reflect.TypeOf(ipn.Prefs{})
+	prefType := reflect.TypeFor[ipn.Prefs]()
 	for _, pref := range prefNames {
 		t := prefType
 		for _, name := range strings.Split(pref, ".") {

+ 1 - 1
control/controlclient/controlclient_test.go

@@ -20,7 +20,7 @@ func fieldsOf(t reflect.Type) (fields []string) {
 func TestStatusEqual(t *testing.T) {
 	// Verify that the Equal method stays in sync with reality
 	equalHandles := []string{"Err", "URL", "NetMap", "Persist", "state"}
-	if have := fieldsOf(reflect.TypeOf(Status{})); !reflect.DeepEqual(have, equalHandles) {
+	if have := fieldsOf(reflect.TypeFor[Status]()); !reflect.DeepEqual(have, equalHandles) {
 		t.Errorf("Status.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
 			have, equalHandles)
 	}

+ 1 - 1
control/controlclient/map.go

@@ -538,7 +538,7 @@ var nodeFields = sync.OnceValue(getNodeFields)
 
 // getNodeFields returns the fails of tailcfg.Node.
 func getNodeFields() []string {
-	rt := reflect.TypeOf((*tailcfg.Node)(nil)).Elem()
+	rt := reflect.TypeFor[tailcfg.Node]()
 	ret := make([]string, rt.NumField())
 	for i := 0; i < rt.NumField(); i++ {
 		ret[i] = rt.Field(i).Name

+ 1 - 1
control/controlknobs/controlknobs_test.go

@@ -15,7 +15,7 @@ func TestAsDebugJSON(t *testing.T) {
 	}
 	k := new(Knobs)
 	got := k.AsDebugJSON()
-	if want := reflect.TypeOf(Knobs{}).NumField(); len(got) != want {
+	if want := reflect.TypeFor[Knobs]().NumField(); len(got) != want {
 		t.Errorf("AsDebugJSON map has %d fields; want %v", len(got), want)
 	}
 }

+ 5 - 5
ipn/prefs_test.go

@@ -64,7 +64,7 @@ func TestPrefsEqual(t *testing.T) {
 		"NetfilterKind",
 		"Persist",
 	}
-	if have := fieldsOf(reflect.TypeOf(Prefs{})); !reflect.DeepEqual(have, prefsHandles) {
+	if have := fieldsOf(reflect.TypeFor[Prefs]()); !reflect.DeepEqual(have, prefsHandles) {
 		t.Errorf("Prefs.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
 			have, prefsHandles)
 	}
@@ -615,14 +615,14 @@ func TestLoadPrefsFileWithZeroInIt(t *testing.T) {
 
 func TestMaskedPrefsFields(t *testing.T) {
 	have := map[string]bool{}
-	for _, f := range fieldsOf(reflect.TypeOf(Prefs{})) {
+	for _, f := range fieldsOf(reflect.TypeFor[Prefs]()) {
 		if f == "Persist" {
 			// This one can't be edited.
 			continue
 		}
 		have[f] = true
 	}
-	for _, f := range fieldsOf(reflect.TypeOf(MaskedPrefs{})) {
+	for _, f := range fieldsOf(reflect.TypeFor[MaskedPrefs]()) {
 		if f == "Prefs" {
 			continue
 		}
@@ -644,8 +644,8 @@ func TestMaskedPrefsFields(t *testing.T) {
 
 	// And also make sure they line up in the right order, which
 	// ApplyEdits assumes.
-	pt := reflect.TypeOf(Prefs{})
-	mt := reflect.TypeOf(MaskedPrefs{})
+	pt := reflect.TypeFor[Prefs]()
+	mt := reflect.TypeFor[MaskedPrefs]()
 	for i := 0; i < mt.NumField(); i++ {
 		name := mt.Field(i).Name
 		if i == 0 {

+ 1 - 1
ssh/tailssh/tailssh_test.go

@@ -1154,7 +1154,7 @@ func TestPathFromPAMEnvLineOnNixOS(t *testing.T) {
 }
 
 func TestStdOsUserUserAssumptions(t *testing.T) {
-	v := reflect.TypeOf(user.User{})
+	v := reflect.TypeFor[user.User]()
 	if got, want := v.NumField(), 5; got != want {
 		t.Errorf("os/user.User has %v fields; this package assumes %v", got, want)
 	}

+ 3 - 3
tailcfg/tailcfg_test.go

@@ -67,7 +67,7 @@ func TestHostinfoEqual(t *testing.T) {
 		"AppConnector",
 		"Location",
 	}
-	if have := fieldsOf(reflect.TypeOf(Hostinfo{})); !reflect.DeepEqual(have, hiHandles) {
+	if have := fieldsOf(reflect.TypeFor[Hostinfo]()); !reflect.DeepEqual(have, hiHandles) {
 		t.Errorf("Hostinfo.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
 			have, hiHandles)
 	}
@@ -364,7 +364,7 @@ func TestNodeEqual(t *testing.T) {
 		"DataPlaneAuditLogID", "Expired", "SelfNodeV4MasqAddrForThisPeer",
 		"SelfNodeV6MasqAddrForThisPeer", "IsWireGuardOnly", "ExitNodeDNSResolvers",
 	}
-	if have := fieldsOf(reflect.TypeOf(Node{})); !reflect.DeepEqual(have, nodeHandles) {
+	if have := fieldsOf(reflect.TypeFor[Node]()); !reflect.DeepEqual(have, nodeHandles) {
 		t.Errorf("Node.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
 			have, nodeHandles)
 	}
@@ -632,7 +632,7 @@ func TestNetInfoFields(t *testing.T) {
 		"DERPLatency",
 		"FirewallMode",
 	}
-	if have := fieldsOf(reflect.TypeOf(NetInfo{})); !reflect.DeepEqual(have, handled) {
+	if have := fieldsOf(reflect.TypeFor[NetInfo]()); !reflect.DeepEqual(have, handled) {
 		t.Errorf("NetInfo.Clone/BasicallyEqually check might be out of sync\nfields: %q\nhandled: %q\n",
 			have, handled)
 	}

+ 1 - 1
types/dnstype/dnstype_test.go

@@ -13,7 +13,7 @@ import (
 
 func TestResolverEqual(t *testing.T) {
 	var fieldNames []string
-	for _, field := range reflect.VisibleFields(reflect.TypeOf(Resolver{})) {
+	for _, field := range reflect.VisibleFields(reflect.TypeFor[Resolver]()) {
 		fieldNames = append(fieldNames, field.Name)
 	}
 	sort.Strings(fieldNames)

+ 1 - 1
types/netmap/nodemut.go

@@ -72,7 +72,7 @@ func (m NodeMutationLastSeen) Apply(n *tailcfg.Node) {
 
 var peerChangeFields = sync.OnceValue(func() []reflect.StructField {
 	var fields []reflect.StructField
-	rt := reflect.TypeOf((*tailcfg.PeerChange)(nil)).Elem()
+	rt := reflect.TypeFor[tailcfg.PeerChange]()
 	for i := 0; i < rt.NumField(); i++ {
 		fields = append(fields, rt.Field(i))
 	}

+ 2 - 2
types/netmap/nodemut_test.go

@@ -27,7 +27,7 @@ func TestMapResponseContainsNonPatchFields(t *testing.T) {
 		case reflect.Bool:
 			return reflect.ValueOf(true)
 		case reflect.String:
-			if reflect.TypeOf(opt.Bool("")) == t {
+			if reflect.TypeFor[opt.Bool]() == t {
 				return reflect.ValueOf("true").Convert(t)
 			}
 			return reflect.ValueOf("foo").Convert(t)
@@ -43,7 +43,7 @@ func TestMapResponseContainsNonPatchFields(t *testing.T) {
 		panic(fmt.Sprintf("unhandled %v", t))
 	}
 
-	rt := reflect.TypeOf(tailcfg.MapResponse{})
+	rt := reflect.TypeFor[tailcfg.MapResponse]()
 	for i := 0; i < rt.NumField(); i++ {
 		f := rt.Field(i)
 

+ 1 - 1
types/persist/persist_test.go

@@ -22,7 +22,7 @@ func fieldsOf(t reflect.Type) (fields []string) {
 
 func TestPersistEqual(t *testing.T) {
 	persistHandles := []string{"LegacyFrontendPrivateMachineKey", "PrivateNodeKey", "OldPrivateNodeKey", "Provider", "UserProfile", "NetworkLockKey", "NodeID", "DisallowedTKAStateIDs"}
-	if have := fieldsOf(reflect.TypeOf(Persist{})); !reflect.DeepEqual(have, persistHandles) {
+	if have := fieldsOf(reflect.TypeFor[Persist]()); !reflect.DeepEqual(have, persistHandles) {
 		t.Errorf("Persist.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
 			have, persistHandles)
 	}

+ 3 - 8
util/ctxkey/key.go

@@ -24,11 +24,6 @@ import (
 	"reflect"
 )
 
-// TODO(https://go.dev/issue/60088): Use reflect.TypeFor instead.
-func reflectTypeFor[T any]() reflect.Type {
-	return reflect.TypeOf((*T)(nil)).Elem()
-}
-
 // Key is a generic key type associated with a specific value type.
 //
 // A zero Key is valid where the Value type itself is used as the context key.
@@ -65,7 +60,7 @@ func New[Value any](name string, defaultValue Value) Key[Value] {
 	// since newly allocated pointers are globally unique within a process.
 	key := Key[Value]{name: new(stringer[string])}
 	if name == "" {
-		name = reflectTypeFor[Value]().String()
+		name = reflect.TypeFor[Value]().String()
 	}
 	key.name.v = name
 	if v := reflect.ValueOf(defaultValue); v.IsValid() && !v.IsZero() {
@@ -78,7 +73,7 @@ func New[Value any](name string, defaultValue Value) Key[Value] {
 func (key Key[Value]) contextKey() any {
 	if key.name == nil {
 		// Use the reflect.Type of the Value (implies key not created by New).
-		return reflectTypeFor[Value]()
+		return reflect.TypeFor[Value]()
 	} else {
 		// Use the name pointer directly (implies key created by New).
 		return key.name
@@ -119,7 +114,7 @@ func (key Key[Value]) Has(ctx context.Context) (ok bool) {
 // String returns the name of the key.
 func (key Key[Value]) String() string {
 	if key.name == nil {
-		return reflectTypeFor[Value]().String()
+		return reflect.TypeFor[Value]().String()
 	}
 	return key.name.String()
 }

+ 3 - 5
util/deephash/deephash.go

@@ -248,7 +248,7 @@ func Hash[T any](v *T) Sum {
 	// Always treat the Hash input as if it were an interface by including
 	// a hash of the type. This ensures that hashing of two different types
 	// but with the same value structure produces different hashes.
-	t := reflect.TypeOf(v).Elem()
+	t := reflect.TypeFor[T]()
 	h.hashType(t)
 	if v == nil {
 		h.HashUint8(0) // indicates nil
@@ -300,8 +300,7 @@ func ExcludeFields[T any](fields ...string) Option {
 }
 
 func newFieldFilter[T any](include bool, fields []string) Option {
-	var zero T
-	t := reflect.TypeOf(&zero).Elem()
+	t := reflect.TypeFor[T]()
 	fieldSet := set.Set[string]{}
 	for _, f := range fields {
 		if _, ok := t.FieldByName(f); !ok {
@@ -321,12 +320,11 @@ func newFieldFilter[T any](include bool, fields []string) Option {
 // be removed in the future, along with documentation about their precedence
 // when combined.
 func HasherForType[T any](opts ...Option) func(*T) Sum {
-	var v *T
 	seedOnce.Do(initSeed)
 	if len(opts) > 1 {
 		panic("HasherForType only accepts one optional argument") // for now
 	}
-	t := reflect.TypeOf(v).Elem()
+	t := reflect.TypeFor[T]()
 	var hash typeHasherFunc
 	for _, o := range opts {
 		switch o := o.(type) {

+ 1 - 1
util/deephash/deephash_test.go

@@ -823,7 +823,7 @@ func TestHashMapAcyclic(t *testing.T) {
 
 	hb := &hashBuffer{Hash: sha256.New()}
 
-	hash := lookupTypeHasher(reflect.TypeOf(m))
+	hash := lookupTypeHasher(reflect.TypeFor[map[int]string]())
 	for i := 0; i < 20; i++ {
 		va := reflect.ValueOf(&m).Elem()
 		hb.Reset()

+ 3 - 3
util/deephash/types.go

@@ -10,9 +10,9 @@ import (
 )
 
 var (
-	timeTimeType   = reflect.TypeOf((*time.Time)(nil)).Elem()
-	netipAddrType  = reflect.TypeOf((*netip.Addr)(nil)).Elem()
-	selfHasherType = reflect.TypeOf((*SelfHasher)(nil)).Elem()
+	timeTimeType   = reflect.TypeFor[time.Time]()
+	netipAddrType  = reflect.TypeFor[netip.Addr]()
+	selfHasherType = reflect.TypeFor[SelfHasher]()
 )
 
 // typeIsSpecialized reports whether this type has specialized hashing.

+ 1 - 1
wgengine/router/router_test.go

@@ -26,7 +26,7 @@ func TestConfigEqual(t *testing.T) {
 		"SubnetRoutes", "SNATSubnetRoutes", "NetfilterMode",
 		"NetfilterKind",
 	}
-	configType := reflect.TypeOf(Config{})
+	configType := reflect.TypeFor[Config]()
 	configFields := []string{}
 	for i := 0; i < configType.NumField(); i++ {
 		configFields = append(configFields, configType.Field(i).Name)

+ 1 - 1
wgengine/wgint/wgint.go

@@ -20,7 +20,7 @@ var (
 )
 
 func getPeerStatsOffset(name string) uintptr {
-	peerType := reflect.TypeOf(device.Peer{})
+	peerType := reflect.TypeFor[device.Peer]()
 	field, ok := peerType.FieldByName(name)
 	if !ok {
 		panic("no " + name + " field in device.Peer")