From 5765c1152209cc4f20c3afcffb18ca0d4367e5f2 Mon Sep 17 00:00:00 2001 From: Alec Thomas Date: Thu, 30 Jan 2025 14:08:07 +1100 Subject: [PATCH] refactor: minor simplification of getMethods --- .golangci.yml | 1 + callbacks.go | 79 +++++++++++++++++++++------------------------------ 2 files changed, 34 insertions(+), 46 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 844092f..3a05633 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -42,6 +42,7 @@ linters: - copyloopvar - intrange - execinquery + - nakedret linters-settings: govet: diff --git a/callbacks.go b/callbacks.go index 4644c54..2a296d0 100644 --- a/callbacks.go +++ b/callbacks.go @@ -81,57 +81,44 @@ func getMethod(value reflect.Value, name string) reflect.Value { // and any embedded fields. // // Returns a slice of bound methods that can be called directly. -func getMethods(value reflect.Value, name string) []reflect.Value { - // Traverses embedded fields of the struct - // starting from the given value to collect all possible receivers - // for the given method name. - var traverse func(value reflect.Value, receivers []reflect.Value) []reflect.Value - traverse = func(value reflect.Value, receivers []reflect.Value) []reflect.Value { - // Always consider the current value for hooks. - receivers = append(receivers, value) - - if value.Kind() == reflect.Ptr { - value = value.Elem() - } - - // If the current value is a struct, also consider embedded fields. - // Two kinds of embedded fields are considered if they're exported: - // - // - standard Go embedded fields - // - fields tagged with `embed:""` - if value.Kind() == reflect.Struct { - t := value.Type() - for i := 0; i < value.NumField(); i++ { - fieldValue := value.Field(i) - field := t.Field(i) - - if !field.IsExported() { - continue - } - - // Consider a field embedded if it's actually embedded - // or if it's tagged with `embed:""`. - _, isEmbedded := field.Tag.Lookup("embed") - isEmbedded = isEmbedded || field.Anonymous - if isEmbedded { - receivers = traverse(fieldValue, receivers) - } - } - } - - return receivers +func getMethods(value reflect.Value, name string) (methods []reflect.Value) { + if value.Kind() == reflect.Ptr { + value = value.Elem() + } + if !value.IsValid() { + return } - receivers := traverse(value, nil /* receivers */) + if method := getMethod(value, name); method.IsValid() { + methods = append(methods, method) + } - // Search all receivers for methods - var methods []reflect.Value - for _, receiver := range receivers { - if method := getMethod(receiver, name); method.IsValid() { - methods = append(methods, method) + if value.Kind() != reflect.Struct { + return + } + // If the current value is a struct, also consider embedded fields. + // Two kinds of embedded fields are considered if they're exported: + // + // - standard Go embedded fields + // - fields tagged with `embed:""` + t := value.Type() + for i := 0; i < value.NumField(); i++ { + fieldValue := value.Field(i) + field := t.Field(i) + + if !field.IsExported() { + continue + } + + // Consider a field embedded if it's actually embedded + // or if it's tagged with `embed:""`. + _, isEmbedded := field.Tag.Lookup("embed") + isEmbedded = isEmbedded || field.Anonymous + if isEmbedded { + methods = append(methods, getMethods(fieldValue, name)...) } } - return methods + return } func callFunction(f reflect.Value, bindings bindings) error {