Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions bundle/direct/dresources/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func loadKeyedSlices(call *calladapt.BoundCaller) (map[string]any, error) {
}

func (a *Adapter) initMethods(resource any) error {
err := calladapt.EnsureNoExtraMethods(resource, calladapt.TypeOf[IResource]())
err := calladapt.EnsureNoExtraMethods(resource, reflect.TypeFor[IResource]())
if err != nil {
return err
}
Expand All @@ -164,7 +164,7 @@ func (a *Adapter) initMethods(resource any) error {
}

// RemapState is optional when remote type already matches state type.
a.remapState, err = calladapt.PrepareCall(resource, calladapt.TypeOf[IResource](), "RemapState")
a.remapState, err = calladapt.PrepareCall(resource, reflect.TypeFor[IResource](), "RemapState")
if err != nil {
return err
}
Expand All @@ -186,37 +186,37 @@ func (a *Adapter) initMethods(resource any) error {

// Optional methods with varying signatures:

a.doUpdate, err = calladapt.PrepareCall(resource, calladapt.TypeOf[IResource](), "DoUpdate")
a.doUpdate, err = calladapt.PrepareCall(resource, reflect.TypeFor[IResource](), "DoUpdate")
if err != nil {
return err
}

a.doUpdateWithID, err = calladapt.PrepareCall(resource, calladapt.TypeOf[IResource](), "DoUpdateWithID")
a.doUpdateWithID, err = calladapt.PrepareCall(resource, reflect.TypeFor[IResource](), "DoUpdateWithID")
if err != nil {
return err
}

a.waitAfterCreate, err = calladapt.PrepareCall(resource, calladapt.TypeOf[IResource](), "WaitAfterCreate")
a.waitAfterCreate, err = calladapt.PrepareCall(resource, reflect.TypeFor[IResource](), "WaitAfterCreate")
if err != nil {
return err
}

a.waitAfterUpdate, err = calladapt.PrepareCall(resource, calladapt.TypeOf[IResource](), "WaitAfterUpdate")
a.waitAfterUpdate, err = calladapt.PrepareCall(resource, reflect.TypeFor[IResource](), "WaitAfterUpdate")
if err != nil {
return err
}

a.overrideChangeDesc, err = calladapt.PrepareCall(resource, calladapt.TypeOf[IResource](), "OverrideChangeDesc")
a.overrideChangeDesc, err = calladapt.PrepareCall(resource, reflect.TypeFor[IResource](), "OverrideChangeDesc")
if err != nil {
return err
}

a.doResize, err = calladapt.PrepareCall(resource, calladapt.TypeOf[IResource](), "DoResize")
a.doResize, err = calladapt.PrepareCall(resource, reflect.TypeFor[IResource](), "DoResize")
if err != nil {
return err
}

keyedSlicesCall, err := calladapt.PrepareCall(resource, calladapt.TypeOf[IResource](), "KeyedSlices")
keyedSlicesCall, err := calladapt.PrepareCall(resource, reflect.TypeFor[IResource](), "KeyedSlices")
if err != nil {
return err
}
Expand Down Expand Up @@ -535,7 +535,7 @@ func (a *Adapter) KeyedSlices() map[string]any {

// prepareCallRequired prepares a call and ensures the method is found.
func prepareCallRequired(resource any, methodName string) (*calladapt.BoundCaller, error) {
caller, err := calladapt.PrepareCall(resource, calladapt.TypeOf[IResource](), methodName)
caller, err := calladapt.PrepareCall(resource, reflect.TypeFor[IResource](), methodName)
if err != nil {
return nil, fmt.Errorf("%s: %w", methodName, err)
}
Expand Down
11 changes: 2 additions & 9 deletions libs/calladapt/calladapt.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@ import (
"reflect"
)

// TypeOf returns reflect.Type for type parameter T, analogous to
// reflect.TypeOf((*T)(nil)).Elem().
func TypeOf[T any]() reflect.Type {
var t *T
return reflect.TypeOf(t).Elem()
}

// BoundCaller encapsulates a bound method and metadata about its signature.
// It can invoke the underlying function and returns all non-error outputs and
// the error (if the method returns one as the last return value).
Expand Down Expand Up @@ -102,8 +95,8 @@ func (c *BoundCaller) Call(args ...any) ([]any, error) {
}

var (
errType = TypeOf[error]()
anyType = TypeOf[any]()
errType = reflect.TypeFor[error]()
anyType = reflect.TypeFor[any]()
)

// PrepareCall creates a unified BoundCaller for the given method on receiver that matches the ifaceType method.
Expand Down
54 changes: 27 additions & 27 deletions libs/calladapt/calladapt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,47 +118,47 @@ func TestPrepareCallErrors(t *testing.T) {
{
name: "void method is supported",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodVoid() }](),
ifaceType: reflect.TypeFor[interface{ PMethodVoid() }](),
method: "PMethodVoid",
},
{
name: "correct number of args - concrete matching argument type",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodAcceptData(data Data) error }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData(data Data) error }](),
method: "PMethodAcceptData",
},
{
name: "correct number of args - interface argument is any",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodAcceptData(data any) error }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData(data any) error }](),
method: "PMethodAcceptData",
},
{
name: "correct number of args - concrete mismatching argument type",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodAcceptData(data NewData) error }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData(data NewData) error }](),
method: "PMethodAcceptData",
errMsg: "interface { PMethodAcceptData(calladapt.NewData) error }.PMethodAcceptData: param 0 mismatch: interface calladapt.NewData, concrete calladapt.Data",
},
{
name: "incorrect number of args",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodAcceptData() error }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData() error }](),
method: "PMethodAcceptData",
errMsg: "interface { PMethodAcceptData() error }.PMethodAcceptData: param count mismatch: interface 0, concrete 1",
},
{
name: "incorrect number of return values",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodAcceptData(any) (any, error) }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData(any) (any, error) }](),
method: "PMethodAcceptData",
errMsg: "interface { PMethodAcceptData(interface {}) (interface {}, error) }.PMethodAcceptData: return count mismatch: interface 2, concrete 1",
unexpected: true,
},
{
name: "error return convertible to any",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodAcceptData(any) any }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData(any) any }](),
method: "PMethodAcceptData",
},
{
Expand All @@ -171,42 +171,42 @@ func TestPrepareCallErrors(t *testing.T) {
{
name: "untyped nil receiver",
recv: nil,
ifaceType: TypeOf[interface{ PMethodAcceptData(any) (any, error) }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData(any) (any, error) }](),
method: "PMethodAcceptData",
errMsg: "first argument must not be untyped nil",
},
{
name: "method is not on interface",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[any](),
ifaceType: reflect.TypeFor[any](),
method: "PMethodAcceptData",
errMsg: "interface {} has no method \"PMethodAcceptData\"",
},
{
name: "method is not on receiver",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ Hello(any) (any, error) }](),
ifaceType: reflect.TypeFor[interface{ Hello(any) (any, error) }](),
method: "Hello",
methodNotFound: true,
},
{
name: "any instead of error allowed",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodAcceptData(data Data) any }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData(data Data) any }](),
method: "PMethodAcceptData",
},
{
name: "error type mismatch",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ GetCustomError() error }](),
ifaceType: reflect.TypeFor[interface{ GetCustomError() error }](),
method: "GetCustomError",
errMsg: "interface { GetCustomError() error }.GetCustomError: result 0 mismatch: interface error, concrete calladapt.CustomError",
unexpected: true,
},
{
name: "two returns without error are supported",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ BadMethod() (int, string) }](),
ifaceType: reflect.TypeFor[interface{ BadMethod() (int, string) }](),
method: "BadMethod",
},
}
Expand Down Expand Up @@ -248,111 +248,111 @@ func TestCall(t *testing.T) {
{
name: "nil receiver - PMethodAcceptData ok",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodAcceptData(data Data) error }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData(data Data) error }](),
method: "PMethodAcceptData",
args: []any{Data{}},
expect: []any{},
},
{
name: "error return",
recv: (*MyStruct)(nil),
ifaceType: TypeOf[interface{ PMethodAcceptData(data Data) error }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptData(data Data) error }](),
method: "PMethodAcceptData",
args: []any{Data{1}},
errMsg: "X cannot be 1",
},
{
name: "value return",
recv: my,
ifaceType: TypeOf[interface{ VMethodTransformNoError(any) any }](),
ifaceType: reflect.TypeFor[interface{ VMethodTransformNoError(any) any }](),
method: "VMethodTransformNoError",
args: []any{Data{2}},
expect: []any{NewData{Y: 12}},
},
{
name: "value return with ptr args",
recv: &my,
ifaceType: TypeOf[interface{ PMethodTransformPtrNoError(any) any }](),
ifaceType: reflect.TypeFor[interface{ PMethodTransformPtrNoError(any) any }](),
method: "PMethodTransformPtrNoError",
args: []any{&Data{2}},
expect: []any{&NewData{Y: 12}},
},
{
name: "any+error return",
recv: &my,
ifaceType: TypeOf[interface{ PMethodTransformData(data Data) (any, error) }](),
ifaceType: reflect.TypeFor[interface{ PMethodTransformData(data Data) (any, error) }](),
method: "PMethodTransformData",
args: []any{Data{2}},
expect: []any{NewData{Y: 22}},
},
{
name: "any+error return, error case",
recv: &MyStruct{State: 0},
ifaceType: TypeOf[interface{ PMethodTransformData(data Data) (any, error) }](),
ifaceType: reflect.TypeFor[interface{ PMethodTransformData(data Data) (any, error) }](),
method: "PMethodTransformData",
args: []any{Data{1}},
errMsg: "X cannot be 1",
},
{
name: "ptr any+error return",
recv: &MyStruct{State: 0},
ifaceType: TypeOf[interface{ PMethodTransformDataPtr(data *Data) (any, error) }](),
ifaceType: reflect.TypeFor[interface{ PMethodTransformDataPtr(data *Data) (any, error) }](),
method: "PMethodTransformDataPtr",
args: []any{&Data{2}},
expect: []any{&NewData{Y: 12}},
},
{
name: "ptr any+error return, error case (nil)",
recv: &MyStruct{State: 0},
ifaceType: TypeOf[interface{ PMethodTransformDataPtr(data *Data) (any, error) }](),
ifaceType: reflect.TypeFor[interface{ PMethodTransformDataPtr(data *Data) (any, error) }](),
method: "PMethodTransformDataPtr",
args: []any{nil},
errMsg: "data is nil",
},
{
name: "void method call returns no outs",
recv: &my,
ifaceType: TypeOf[interface{ PMethodVoid() }](),
ifaceType: reflect.TypeFor[interface{ PMethodVoid() }](),
method: "PMethodVoid",
args: []any{},
expect: []any{},
},
{
name: "too many args error",
recv: my,
ifaceType: TypeOf[interface{ VMethodTransformNoError(data Data) any }](),
ifaceType: reflect.TypeFor[interface{ VMethodTransformNoError(data Data) any }](),
method: "VMethodTransformNoError",
args: []any{Data{1}, Data{2}},
errMsg: "VMethodTransformNoError: want 1 args, got 2",
},
{
name: "wrong arg type error (different pointer)",
recv: &my,
ifaceType: TypeOf[interface{ PMethodTransformPtrNoError(data *Data) any }](),
ifaceType: reflect.TypeFor[interface{ PMethodTransformPtrNoError(data *Data) any }](),
method: "PMethodTransformPtrNoError",
args: []any{&NewData{}},
errMsg: "PMethodTransformPtrNoError: arg 0 type mismatch: want *calladapt.Data, got *calladapt.NewData",
},
{
name: "nil interface param allowed",
recv: &my,
ifaceType: TypeOf[interface{ PMethodAcceptAny(v any) error }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptAny(v any) error }](),
method: "PMethodAcceptAny",
args: []any{nil},
errMsg: "PMethodAcceptAny: arg 0 type mismatch: want interface {}, got nil",
},
{
name: "nil slice param allowed",
recv: &my,
ifaceType: TypeOf[interface{ PMethodAcceptSlice(s []int) int }](),
ifaceType: reflect.TypeFor[interface{ PMethodAcceptSlice(s []int) int }](),
method: "PMethodAcceptSlice",
args: []any{nil},
errMsg: "PMethodAcceptSlice: arg 0 type mismatch: want []int, got nil",
},
{
name: "DoCreate returns id",
recv: &my,
ifaceType: TypeOf[interface {
ifaceType: reflect.TypeFor[interface {
DoCreate(ctx context.Context, data *Data) (string, error)
}](),
method: "DoCreate",
Expand Down
7 changes: 4 additions & 3 deletions libs/calladapt/validate_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package calladapt_test

import (
"reflect"
"testing"

"github.com/databricks/cli/libs/calladapt"
Expand Down Expand Up @@ -32,19 +33,19 @@ func (*badType) Extra() {}

func TestEnsureNoExtraMethods_AllowsPartial(t *testing.T) {
typedNil := (*partialType)(nil)
err := calladapt.EnsureNoExtraMethods(typedNil, calladapt.TypeOf[testIface]())
err := calladapt.EnsureNoExtraMethods(typedNil, reflect.TypeFor[testIface]())
require.NoError(t, err)
}

func TestEnsureNoExtraMethods_AllowsGood(t *testing.T) {
typedNil := (*goodType)(nil)
err := calladapt.EnsureNoExtraMethods(typedNil, calladapt.TypeOf[testIface]())
err := calladapt.EnsureNoExtraMethods(typedNil, reflect.TypeFor[testIface]())
require.NoError(t, err)
}

func TestEnsureNoExtraMethods_RejectsExtra(t *testing.T) {
typedNil := (*badType)(nil)
err := calladapt.EnsureNoExtraMethods(typedNil, calladapt.TypeOf[testIface]())
err := calladapt.EnsureNoExtraMethods(typedNil, reflect.TypeFor[testIface]())
require.Error(t, err)
assert.Equal(t, "unexpected method Extra on *calladapt_test.badType; only methods from [calladapt_test.testIface] are allowed", err.Error())
}
Expand Down
2 changes: 1 addition & 1 deletion libs/dyn/convert/struct_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func (s *structInfo) FieldValues(v reflect.Value) []FieldValue {
}

// Type of [dyn.Value].
var configValueType = reflect.TypeOf((*dyn.Value)(nil)).Elem()
var configValueType = reflect.TypeFor[dyn.Value]()

// getForceSendFieldsValues collects ForceSendFields reflect.Values
// Returns map[structKey]reflect.Value where structKey is -1 for direct fields, embedded index for embedded fields
Expand Down
9 changes: 9 additions & 0 deletions libs/gorules/rule_reflect_typefor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gorules

import "github.com/quasilyte/go-ruleguard/dsl"

// UseReflectTypeFor detects reflect.TypeOf((*T)(nil)).Elem() and suggests reflect.TypeFor[T]() instead.
func UseReflectTypeFor(m dsl.Matcher) {
m.Match(`reflect.TypeOf(($x)(nil)).Elem()`).
Report(`Use reflect.TypeFor instead of reflect.TypeOf((*T)(nil)).Elem()`)
}
2 changes: 1 addition & 1 deletion libs/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func SortedKeys[T any](m map[string]T) []string {
// We must use that when copying structs because JSON marshaller in SDK crashes if it sees unknown field.
func FilterFields[T any](fields []string, excludeFields ...string) []string {
var result []string
typeOfT := reflect.TypeOf((*T)(nil)).Elem()
typeOfT := reflect.TypeFor[T]()

excludeMap := make(map[string]bool)
for _, exclude := range excludeFields {
Expand Down
Loading