diff options
author | Joe Tsai <joetsai@digital-static.net> | 2019-02-16 18:41:22 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-16 18:41:22 -0800 |
commit | ba10d0b4aceae4ab62c99f38b61d600756d7533b (patch) | |
tree | e4339a135f453d6b99a332447e2eb84cc33b401d /cmp/internal | |
parent | 47b0945204f5ee05a89cc15d92eec97315340c50 (diff) | |
download | go-cmp-ba10d0b4aceae4ab62c99f38b61d600756d7533b.tar.gz |
Move function name logic to function package (#106)
Adjust the logic of NameOf for more recent versions of Go.
Diffstat (limited to 'cmp/internal')
-rw-r--r-- | cmp/internal/function/func.go | 42 | ||||
-rw-r--r-- | cmp/internal/function/func_test.go | 51 |
2 files changed, 91 insertions, 2 deletions
diff --git a/cmp/internal/function/func.go b/cmp/internal/function/func.go index 4c35ff1..1b4c4c5 100644 --- a/cmp/internal/function/func.go +++ b/cmp/internal/function/func.go @@ -2,10 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE.md file. -// Package function identifies function types. +// Package function provides functionality for identifying function types. package function -import "reflect" +import ( + "reflect" + "regexp" + "runtime" + "strings" +) type funcType int @@ -47,3 +52,36 @@ func IsType(t reflect.Type, ft funcType) bool { } return false } + +var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`) + +// NameOf returns the name of the function value. +func NameOf(v reflect.Value) string { + fnc := runtime.FuncForPC(v.Pointer()) + if fnc == nil { + return "<unknown>" + } + fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm" + + // Method closures have a "-fm" suffix. + fullName = strings.TrimSuffix(fullName, "-fm") + + var name string + for len(fullName) > 0 { + inParen := strings.HasSuffix(fullName, ")") + fullName = strings.TrimSuffix(fullName, ")") + + s := lastIdentRx.FindString(fullName) + if s == "" { + break + } + name = s + "." + name + fullName = strings.TrimSuffix(fullName, s) + + if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 { + fullName = fullName[:i] + } + fullName = strings.TrimSuffix(fullName, ".") + } + return strings.TrimSuffix(name, ".") +} diff --git a/cmp/internal/function/func_test.go b/cmp/internal/function/func_test.go new file mode 100644 index 0000000..61eeccd --- /dev/null +++ b/cmp/internal/function/func_test.go @@ -0,0 +1,51 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package function + +import ( + "bytes" + "reflect" + "testing" +) + +type myType struct{ bytes.Buffer } + +func (myType) valueMethod() {} +func (myType) ValueMethod() {} + +func (*myType) pointerMethod() {} +func (*myType) PointerMethod() {} + +func TestNameOf(t *testing.T) { + tests := []struct { + fnc interface{} + want string + }{ + {TestNameOf, "function.TestNameOf"}, + {func() {}, "function.TestNameOf.func1"}, + {(myType).valueMethod, "function.myType.valueMethod"}, + {(myType).ValueMethod, "function.myType.ValueMethod"}, + {(myType{}).valueMethod, "function.myType.valueMethod"}, + {(myType{}).ValueMethod, "function.myType.ValueMethod"}, + {(*myType).valueMethod, "function.myType.valueMethod"}, + {(*myType).ValueMethod, "function.myType.ValueMethod"}, + {(&myType{}).valueMethod, "function.myType.valueMethod"}, + {(&myType{}).ValueMethod, "function.myType.ValueMethod"}, + {(*myType).pointerMethod, "function.myType.pointerMethod"}, + {(*myType).PointerMethod, "function.myType.PointerMethod"}, + {(&myType{}).pointerMethod, "function.myType.pointerMethod"}, + {(&myType{}).PointerMethod, "function.myType.PointerMethod"}, + {(*myType).Write, "function.myType.Write"}, + {(&myType{}).Write, "bytes.Buffer.Write"}, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + got := NameOf(reflect.ValueOf(tt.fnc)) + if got != tt.want { + t.Errorf("NameOf() = %v, want %v", got, tt.want) + } + }) + } +} |