xref: /aosp_15_r20/external/go-cmp/cmp/internal/function/func.go (revision 88d15eac089d7f20c739ff1001d56b91872b21a1)
1*88d15eacSSasha Smundak// Copyright 2017, The Go Authors. All rights reserved.
2*88d15eacSSasha Smundak// Use of this source code is governed by a BSD-style
3*88d15eacSSasha Smundak// license that can be found in the LICENSE file.
4*88d15eacSSasha Smundak
5*88d15eacSSasha Smundak// Package function provides functionality for identifying function types.
6*88d15eacSSasha Smundakpackage function
7*88d15eacSSasha Smundak
8*88d15eacSSasha Smundakimport (
9*88d15eacSSasha Smundak	"reflect"
10*88d15eacSSasha Smundak	"regexp"
11*88d15eacSSasha Smundak	"runtime"
12*88d15eacSSasha Smundak	"strings"
13*88d15eacSSasha Smundak)
14*88d15eacSSasha Smundak
15*88d15eacSSasha Smundaktype funcType int
16*88d15eacSSasha Smundak
17*88d15eacSSasha Smundakconst (
18*88d15eacSSasha Smundak	_ funcType = iota
19*88d15eacSSasha Smundak
20*88d15eacSSasha Smundak	tbFunc  // func(T) bool
21*88d15eacSSasha Smundak	ttbFunc // func(T, T) bool
22*88d15eacSSasha Smundak	trbFunc // func(T, R) bool
23*88d15eacSSasha Smundak	tibFunc // func(T, I) bool
24*88d15eacSSasha Smundak	trFunc  // func(T) R
25*88d15eacSSasha Smundak
26*88d15eacSSasha Smundak	Equal             = ttbFunc // func(T, T) bool
27*88d15eacSSasha Smundak	EqualAssignable   = tibFunc // func(T, I) bool; encapsulates func(T, T) bool
28*88d15eacSSasha Smundak	Transformer       = trFunc  // func(T) R
29*88d15eacSSasha Smundak	ValueFilter       = ttbFunc // func(T, T) bool
30*88d15eacSSasha Smundak	Less              = ttbFunc // func(T, T) bool
31*88d15eacSSasha Smundak	ValuePredicate    = tbFunc  // func(T) bool
32*88d15eacSSasha Smundak	KeyValuePredicate = trbFunc // func(T, R) bool
33*88d15eacSSasha Smundak)
34*88d15eacSSasha Smundak
35*88d15eacSSasha Smundakvar boolType = reflect.TypeOf(true)
36*88d15eacSSasha Smundak
37*88d15eacSSasha Smundak// IsType reports whether the reflect.Type is of the specified function type.
38*88d15eacSSasha Smundakfunc IsType(t reflect.Type, ft funcType) bool {
39*88d15eacSSasha Smundak	if t == nil || t.Kind() != reflect.Func || t.IsVariadic() {
40*88d15eacSSasha Smundak		return false
41*88d15eacSSasha Smundak	}
42*88d15eacSSasha Smundak	ni, no := t.NumIn(), t.NumOut()
43*88d15eacSSasha Smundak	switch ft {
44*88d15eacSSasha Smundak	case tbFunc: // func(T) bool
45*88d15eacSSasha Smundak		if ni == 1 && no == 1 && t.Out(0) == boolType {
46*88d15eacSSasha Smundak			return true
47*88d15eacSSasha Smundak		}
48*88d15eacSSasha Smundak	case ttbFunc: // func(T, T) bool
49*88d15eacSSasha Smundak		if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType {
50*88d15eacSSasha Smundak			return true
51*88d15eacSSasha Smundak		}
52*88d15eacSSasha Smundak	case trbFunc: // func(T, R) bool
53*88d15eacSSasha Smundak		if ni == 2 && no == 1 && t.Out(0) == boolType {
54*88d15eacSSasha Smundak			return true
55*88d15eacSSasha Smundak		}
56*88d15eacSSasha Smundak	case tibFunc: // func(T, I) bool
57*88d15eacSSasha Smundak		if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType {
58*88d15eacSSasha Smundak			return true
59*88d15eacSSasha Smundak		}
60*88d15eacSSasha Smundak	case trFunc: // func(T) R
61*88d15eacSSasha Smundak		if ni == 1 && no == 1 {
62*88d15eacSSasha Smundak			return true
63*88d15eacSSasha Smundak		}
64*88d15eacSSasha Smundak	}
65*88d15eacSSasha Smundak	return false
66*88d15eacSSasha Smundak}
67*88d15eacSSasha Smundak
68*88d15eacSSasha Smundakvar lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`)
69*88d15eacSSasha Smundak
70*88d15eacSSasha Smundak// NameOf returns the name of the function value.
71*88d15eacSSasha Smundakfunc NameOf(v reflect.Value) string {
72*88d15eacSSasha Smundak	fnc := runtime.FuncForPC(v.Pointer())
73*88d15eacSSasha Smundak	if fnc == nil {
74*88d15eacSSasha Smundak		return "<unknown>"
75*88d15eacSSasha Smundak	}
76*88d15eacSSasha Smundak	fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm"
77*88d15eacSSasha Smundak
78*88d15eacSSasha Smundak	// Method closures have a "-fm" suffix.
79*88d15eacSSasha Smundak	fullName = strings.TrimSuffix(fullName, "-fm")
80*88d15eacSSasha Smundak
81*88d15eacSSasha Smundak	var name string
82*88d15eacSSasha Smundak	for len(fullName) > 0 {
83*88d15eacSSasha Smundak		inParen := strings.HasSuffix(fullName, ")")
84*88d15eacSSasha Smundak		fullName = strings.TrimSuffix(fullName, ")")
85*88d15eacSSasha Smundak
86*88d15eacSSasha Smundak		s := lastIdentRx.FindString(fullName)
87*88d15eacSSasha Smundak		if s == "" {
88*88d15eacSSasha Smundak			break
89*88d15eacSSasha Smundak		}
90*88d15eacSSasha Smundak		name = s + "." + name
91*88d15eacSSasha Smundak		fullName = strings.TrimSuffix(fullName, s)
92*88d15eacSSasha Smundak
93*88d15eacSSasha Smundak		if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 {
94*88d15eacSSasha Smundak			fullName = fullName[:i]
95*88d15eacSSasha Smundak		}
96*88d15eacSSasha Smundak		fullName = strings.TrimSuffix(fullName, ".")
97*88d15eacSSasha Smundak	}
98*88d15eacSSasha Smundak	return strings.TrimSuffix(name, ".")
99*88d15eacSSasha Smundak}
100