1 | // Copyright 2008 Google Inc. |
2 | // All Rights Reserved. |
3 | // |
4 | // Redistribution and use in source and binary forms, with or without |
5 | // modification, are permitted provided that the following conditions are |
6 | // met: |
7 | // |
8 | // * Redistributions of source code must retain the above copyright |
9 | // notice, this list of conditions and the following disclaimer. |
10 | // * Redistributions in binary form must reproduce the above |
11 | // copyright notice, this list of conditions and the following disclaimer |
12 | // in the documentation and/or other materials provided with the |
13 | // distribution. |
14 | // * Neither the name of Google Inc. nor the names of its |
15 | // contributors may be used to endorse or promote products derived from |
16 | // this software without specific prior written permission. |
17 | // |
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | |
30 | // Type utilities needed for implementing typed and type-parameterized |
31 | // tests. |
32 | |
33 | // IWYU pragma: private, include "gtest/gtest.h" |
34 | // IWYU pragma: friend gtest/.* |
35 | // IWYU pragma: friend gmock/.* |
36 | |
37 | #ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ |
38 | #define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ |
39 | |
40 | #include <string> |
41 | #include <type_traits> |
42 | #include <typeinfo> |
43 | |
44 | #include "gtest/internal/gtest-port.h" |
45 | |
46 | // #ifdef __GNUC__ is too general here. It is possible to use gcc without using |
47 | // libstdc++ (which is where cxxabi.h comes from). |
48 | #if GTEST_HAS_CXXABI_H_ |
49 | #include <cxxabi.h> |
50 | #elif defined(__HP_aCC) |
51 | #include <acxx_demangle.h> |
52 | #endif // GTEST_HASH_CXXABI_H_ |
53 | |
54 | namespace testing { |
55 | namespace internal { |
56 | |
57 | // Canonicalizes a given name with respect to the Standard C++ Library. |
58 | // This handles removing the inline namespace within `std` that is |
59 | // used by various standard libraries (e.g., `std::__1`). Names outside |
60 | // of namespace std are returned unmodified. |
61 | inline std::string CanonicalizeForStdLibVersioning(std::string s) { |
62 | static const char prefix[] = "std::__" ; |
63 | if (s.compare(pos: 0, n1: strlen(s: prefix), s: prefix) == 0) { |
64 | std::string::size_type end = s.find(s: "::" , pos: strlen(s: prefix)); |
65 | if (end != s.npos) { |
66 | // Erase everything between the initial `std` and the second `::`. |
67 | s.erase(pos: strlen(s: "std" ), n: end - strlen(s: "std" )); |
68 | } |
69 | } |
70 | |
71 | // Strip redundant spaces in typename to match MSVC |
72 | // For example, std::pair<int, bool> -> std::pair<int,bool> |
73 | static const char to_search[] = ", " ; |
74 | static const char replace_str[] = "," ; |
75 | size_t pos = 0; |
76 | while (true) { |
77 | // Get the next occurrence from the current position |
78 | pos = s.find(s: to_search, pos: pos); |
79 | if (pos == std::string::npos) { |
80 | break; |
81 | } |
82 | // Replace this occurrence of substring |
83 | s.replace(pos: pos, n1: strlen(s: to_search), s: replace_str); |
84 | pos += strlen(s: replace_str); |
85 | } |
86 | return s; |
87 | } |
88 | |
89 | #if GTEST_HAS_RTTI |
90 | // GetTypeName(const std::type_info&) returns a human-readable name of type T. |
91 | inline std::string GetTypeName(const std::type_info& type) { |
92 | const char* const name = type.name(); |
93 | #if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) |
94 | int status = 0; |
95 | // gcc's implementation of typeid(T).name() mangles the type name, |
96 | // so we have to demangle it. |
97 | #if GTEST_HAS_CXXABI_H_ |
98 | using abi::__cxa_demangle; |
99 | #endif // GTEST_HAS_CXXABI_H_ |
100 | char* const readable_name = __cxa_demangle(mangled_name: name, output_buffer: nullptr, length: nullptr, status: &status); |
101 | const std::string name_str(status == 0 ? readable_name : name); |
102 | free(ptr: readable_name); |
103 | return CanonicalizeForStdLibVersioning(s: name_str); |
104 | #elif defined(_MSC_VER) |
105 | // Strip struct and class due to differences between |
106 | // MSVC and other compilers. std::pair<int,bool> is printed as |
107 | // "struct std::pair<int,bool>" when using MSVC vs "std::pair<int, bool>" with |
108 | // other compilers. |
109 | std::string s = name; |
110 | // Only strip the leading "struct " and "class ", so uses rfind == 0 to |
111 | // ensure that |
112 | if (s.rfind("struct " , 0) == 0) { |
113 | s = s.substr(strlen("struct " )); |
114 | } else if (s.rfind("class " , 0) == 0) { |
115 | s = s.substr(strlen("class " )); |
116 | } |
117 | return s; |
118 | #else |
119 | return name; |
120 | #endif // GTEST_HAS_CXXABI_H_ || __HP_aCC |
121 | } |
122 | #endif // GTEST_HAS_RTTI |
123 | |
124 | // GetTypeName<T>() returns a human-readable name of type T if and only if |
125 | // RTTI is enabled, otherwise it returns a dummy type name. |
126 | // NB: This function is also used in Google Mock, so don't move it inside of |
127 | // the typed-test-only section below. |
128 | template <typename T> |
129 | std::string GetTypeName() { |
130 | #if GTEST_HAS_RTTI |
131 | return GetTypeName(type: typeid(T)); |
132 | #else |
133 | return "<type>" ; |
134 | #endif // GTEST_HAS_RTTI |
135 | } |
136 | |
137 | // A unique type indicating an empty node |
138 | struct None {}; |
139 | |
140 | #define GTEST_TEMPLATE_ \ |
141 | template <typename T> \ |
142 | class |
143 | |
144 | // The template "selector" struct TemplateSel<Tmpl> is used to |
145 | // represent Tmpl, which must be a class template with one type |
146 | // parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined |
147 | // as the type Tmpl<T>. This allows us to actually instantiate the |
148 | // template "selected" by TemplateSel<Tmpl>. |
149 | // |
150 | // This trick is necessary for simulating typedef for class templates, |
151 | // which C++ doesn't support directly. |
152 | template <GTEST_TEMPLATE_ Tmpl> |
153 | struct TemplateSel { |
154 | template <typename T> |
155 | struct Bind { |
156 | typedef Tmpl<T> type; |
157 | }; |
158 | }; |
159 | |
160 | #define GTEST_BIND_(TmplSel, T) TmplSel::template Bind<T>::type |
161 | |
162 | template <GTEST_TEMPLATE_ Head_, GTEST_TEMPLATE_... Tail_> |
163 | struct Templates { |
164 | using Head = TemplateSel<Head_>; |
165 | using Tail = Templates<Tail_...>; |
166 | }; |
167 | |
168 | template <GTEST_TEMPLATE_ Head_> |
169 | struct Templates<Head_> { |
170 | using Head = TemplateSel<Head_>; |
171 | using Tail = None; |
172 | }; |
173 | |
174 | // Tuple-like type lists |
175 | template <typename Head_, typename... Tail_> |
176 | struct Types { |
177 | using Head = Head_; |
178 | using Tail = Types<Tail_...>; |
179 | }; |
180 | |
181 | template <typename Head_> |
182 | struct Types<Head_> { |
183 | using Head = Head_; |
184 | using Tail = None; |
185 | }; |
186 | |
187 | // Helper metafunctions to tell apart a single type from types |
188 | // generated by ::testing::Types |
189 | template <typename... Ts> |
190 | struct ProxyTypeList { |
191 | using type = Types<Ts...>; |
192 | }; |
193 | |
194 | template <typename> |
195 | struct is_proxy_type_list : std::false_type {}; |
196 | |
197 | template <typename... Ts> |
198 | struct is_proxy_type_list<ProxyTypeList<Ts...>> : std::true_type {}; |
199 | |
200 | // Generator which conditionally creates type lists. |
201 | // It recognizes if a requested type list should be created |
202 | // and prevents creating a new type list nested within another one. |
203 | template <typename T> |
204 | struct GenerateTypeList { |
205 | private: |
206 | using proxy = typename std::conditional<is_proxy_type_list<T>::value, T, |
207 | ProxyTypeList<T>>::type; |
208 | |
209 | public: |
210 | using type = typename proxy::type; |
211 | }; |
212 | |
213 | } // namespace internal |
214 | |
215 | template <typename... Ts> |
216 | using Types = internal::ProxyTypeList<Ts...>; |
217 | |
218 | } // namespace testing |
219 | |
220 | #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ |
221 | |