aboutsummaryrefslogtreecommitdiff
path: root/brillo
diff options
context:
space:
mode:
authorAlex Vakulenko <avakulenko@google.com>2015-12-21 12:05:41 -0800
committerAlex Vakulenko <avakulenko@google.com>2016-01-04 11:12:48 -0800
commit4d8501c1f9689c833d38c9087df28b971a6ebe42 (patch)
tree02dc0e9696579855b42296d94aaee90f1ea896f1 /brillo
parent2fd46ba1458275cd16b0949675bff70cc8abcdad (diff)
downloadlibbrillo-4d8501c1f9689c833d38c9087df28b971a6ebe42.tar.gz
libbrillo: Remove RTTI from the library
The main reason why we needed run-time type information is so that we can get a type name string for a particular type T. This string was used in type comparisons in brillo::Any as the only reliable way of determining if two Any instances have values of the same type. For this typeid(T).name() was used which requires RTTI to be enabled. However using RTTI causes issues when linking to libraries with RTTI disabled. To resolve this issue, stop relying on RTTI in libbrillo and throughout the rest of Brillo code. A special work-around was implemented to obtain a type name for a given type, which relies on the fact that __PRETTY_FUNCTION__ macro on GCC/clang includes the full signature of a method, including any template parameters. For example, brillo::GetTypeTag<double>() would return const char *brillo::GetTypeTag() [T = double] and extracting the type name ("double") is just a matter of simple string manipulations. To speed up the code at run-time, we don't really need to extract the type name from this function name when comparing two types, but rather compare the two function names directly. This function name with embedded type is called "type tag" in the code. Unfortunately GCC and CLANG handle __PRETTY_FUNCTION__ differently for certain template types, so added #error statement to force compiling using clang only (since this is the compiler used most often for Brillo targets). BUG: 26292405 Change-Id: Ie70012b62f66911ee7787e5cf7eeab88359bd959
Diffstat (limited to 'brillo')
-rw-r--r--brillo/any.cc6
-rw-r--r--brillo/any.h22
-rw-r--r--brillo/any_internal_impl.h8
-rw-r--r--brillo/any_internal_impl_unittest.cc31
-rw-r--r--brillo/any_unittest.cc14
-rw-r--r--brillo/dbus/exported_property_set_unittest.cc2
-rw-r--r--brillo/type_name_undecorate.cc35
-rw-r--r--brillo/type_name_undecorate.h44
-rw-r--r--brillo/type_name_undecorate_unittest.cc61
9 files changed, 172 insertions, 51 deletions
diff --git a/brillo/any.cc b/brillo/any.cc
index d2313c5..f84badf 100644
--- a/brillo/any.cc
+++ b/brillo/any.cc
@@ -34,7 +34,7 @@ Any& Any::operator=(Any&& rhs) {
bool Any::operator==(const Any& rhs) const {
// Make sure both objects contain data of the same type.
- if (strcmp(GetTypeNameInternal(), rhs.GetTypeNameInternal()) != 0)
+ if (strcmp(GetTypeTagInternal(), rhs.GetTypeTagInternal()) != 0)
return false;
if (IsEmpty())
@@ -43,9 +43,9 @@ bool Any::operator==(const Any& rhs) const {
return data_buffer_.GetDataPtr()->CompareEqual(rhs.data_buffer_.GetDataPtr());
}
-const char* Any::GetTypeNameInternal() const {
+const char* Any::GetTypeTagInternal() const {
if (!IsEmpty())
- return data_buffer_.GetDataPtr()->GetTypeName();
+ return data_buffer_.GetDataPtr()->GetTypeTag();
return "";
}
diff --git a/brillo/any.h b/brillo/any.h
index feedc73..51016b5 100644
--- a/brillo/any.h
+++ b/brillo/any.h
@@ -83,8 +83,8 @@ class BRILLO_EXPORT Any final {
// to make sure the requested type matches the type of data actually stored,
// so this "canonical" type is used for type checking below.
using CanonicalDestType = typename std::decay<DestType>::type;
- const char* contained_type = GetTypeNameInternal();
- if (strcmp(typeid(CanonicalDestType).name(), contained_type) == 0)
+ const char* contained_type = GetTypeTagInternal();
+ if (strcmp(GetTypeTag<CanonicalDestType>(), contained_type) == 0)
return true;
if (!std::is_pointer<CanonicalDestType>::value)
@@ -97,17 +97,17 @@ class BRILLO_EXPORT Any final {
using NonPointer = typename std::remove_pointer<CanonicalDestType>::type;
using CanonicalDestTypeNoConst = typename std::add_pointer<
typename std::remove_const<NonPointer>::type>::type;
- if (strcmp(typeid(CanonicalDestTypeNoConst).name(), contained_type) == 0)
+ if (strcmp(GetTypeTag<CanonicalDestTypeNoConst>(), contained_type) == 0)
return true;
using CanonicalDestTypeNoVolatile = typename std::add_pointer<
typename std::remove_volatile<NonPointer>::type>::type;
- if (strcmp(typeid(CanonicalDestTypeNoVolatile).name(), contained_type) == 0)
+ if (strcmp(GetTypeTag<CanonicalDestTypeNoVolatile>(), contained_type) == 0)
return true;
using CanonicalDestTypeNoConstOrVolatile = typename std::add_pointer<
typename std::remove_cv<NonPointer>::type>::type;
- return strcmp(typeid(CanonicalDestTypeNoConstOrVolatile).name(),
+ return strcmp(GetTypeTag<CanonicalDestTypeNoConstOrVolatile>(),
contained_type) == 0;
}
@@ -162,13 +162,9 @@ class BRILLO_EXPORT Any final {
return TryGet<T>(typename std::decay<T>::type());
}
- // Returns the name of the type contained within Any. The string is a mangled
- // type name returned by type_info::name(). For most cases, instead of using
- // this function, you should be calling IsTypeCompatible<>().
- inline std::string GetTypeName() const { return GetTypeNameInternal(); }
// Returns the undecorated name of the type contained within Any.
inline std::string GetUndecoratedTypeName() const {
- return UndecorateTypeName(GetTypeNameInternal());
+ return GetUndecoratedTypeNameForTag(GetTypeTagInternal());
}
// Swaps the value of this object with that of |other|.
void Swap(Any& other);
@@ -196,9 +192,9 @@ class BRILLO_EXPORT Any final {
void AppendToDBusMessageWriter(dbus::MessageWriter* writer) const;
private:
- // Internal implementation of GetTypeName() which returns just a char* to
- // static type name buffer.
- const char* GetTypeNameInternal() const;
+ // Returns a pointer to a static buffer containing type tag (sort of a type
+ // name) of the contained value.
+ const char* GetTypeTagInternal() const;
// The data buffer for contained object.
internal_details::Buffer data_buffer_;
diff --git a/brillo/any_internal_impl.h b/brillo/any_internal_impl.h
index d4fa39e..0154d4d 100644
--- a/brillo/any_internal_impl.h
+++ b/brillo/any_internal_impl.h
@@ -142,8 +142,8 @@ class Buffer; // Forward declaration of data buffer container.
// Abstract base class for contained variant data.
struct Data {
virtual ~Data() {}
- // Returns the type name for the contained data.
- virtual const char* GetTypeName() const = 0;
+ // Returns the type tag (name) for the contained data.
+ virtual const char* GetTypeTag() const = 0;
// Copies the contained data to the output |buffer|.
virtual void CopyTo(Buffer* buffer) const = 0;
// Moves the contained data to the output |buffer|.
@@ -165,7 +165,7 @@ struct TypedData : public Data {
// NOLINTNEXTLINE(build/c++11)
explicit TypedData(T&& value) : value_(std::move(value)) {}
- const char* GetTypeName() const override { return typeid(T).name(); }
+ const char* GetTypeTag() const override { return brillo::GetTypeTag<T>(); }
void CopyTo(Buffer* buffer) const override;
void MoveTo(Buffer* buffer) override;
bool IsConvertibleToInteger() const override {
@@ -268,7 +268,7 @@ class Buffer final {
using Type = typename std::decay<T>::type;
using DataType = TypedData<Type>;
Data* ptr = GetDataPtr();
- if (ptr && strcmp(ptr->GetTypeName(), typeid(Type).name()) == 0) {
+ if (ptr && strcmp(ptr->GetTypeTag(), GetTypeTag<Type>()) == 0) {
// We assign the data to the variant container, which already
// has the data of the same type. Do fast copy/move with no memory
// reallocation.
diff --git a/brillo/any_internal_impl_unittest.cc b/brillo/any_internal_impl_unittest.cc
index 4f39939..6f7f512 100644
--- a/brillo/any_internal_impl_unittest.cc
+++ b/brillo/any_internal_impl_unittest.cc
@@ -8,6 +8,7 @@
#include <gtest/gtest.h>
using brillo::internal_details::Buffer;
+using brillo::GetTypeTag;
TEST(Buffer, Empty) {
Buffer buffer;
@@ -21,7 +22,7 @@ TEST(Buffer, Store_Int) {
buffer.Assign(2);
EXPECT_FALSE(buffer.IsEmpty());
EXPECT_EQ(Buffer::kContained, buffer.storage_);
- EXPECT_STREQ(typeid(int).name(), buffer.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<int>(), buffer.GetDataPtr()->GetTypeTag());
}
TEST(Buffer, Store_Double) {
@@ -29,7 +30,7 @@ TEST(Buffer, Store_Double) {
buffer.Assign(2.3);
EXPECT_FALSE(buffer.IsEmpty());
EXPECT_EQ(Buffer::kContained, buffer.storage_);
- EXPECT_STREQ(typeid(double).name(), buffer.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<double>(), buffer.GetDataPtr()->GetTypeTag());
}
TEST(Buffer, Store_Pointers) {
@@ -38,14 +39,14 @@ TEST(Buffer, Store_Pointers) {
buffer.Assign(nullptr);
EXPECT_FALSE(buffer.IsEmpty());
EXPECT_EQ(Buffer::kContained, buffer.storage_);
- EXPECT_STREQ(typeid(std::nullptr_t).name(),
- buffer.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<std::nullptr_t>(),
+ buffer.GetDataPtr()->GetTypeTag());
// char *
buffer.Assign("abcd");
EXPECT_FALSE(buffer.IsEmpty());
EXPECT_EQ(Buffer::kContained, buffer.storage_);
- EXPECT_STREQ(typeid(const char*).name(), buffer.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<const char*>(), buffer.GetDataPtr()->GetTypeTag());
// pointer to non-trivial object
class NonTrivial {
@@ -55,7 +56,7 @@ TEST(Buffer, Store_Pointers) {
buffer.Assign(&non_trivial);
EXPECT_FALSE(buffer.IsEmpty());
EXPECT_EQ(Buffer::kContained, buffer.storage_);
- EXPECT_STREQ(typeid(NonTrivial*).name(), buffer.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<NonTrivial*>(), buffer.GetDataPtr()->GetTypeTag());
}
TEST(Buffer, Store_NonTrivialObjects) {
@@ -67,7 +68,7 @@ TEST(Buffer, Store_NonTrivialObjects) {
buffer.Assign(non_trivial);
EXPECT_FALSE(buffer.IsEmpty());
EXPECT_EQ(Buffer::kExternal, buffer.storage_);
- EXPECT_STREQ(typeid(NonTrivial).name(), buffer.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<NonTrivial>(), buffer.GetDataPtr()->GetTypeTag());
}
TEST(Buffer, Store_Objects) {
@@ -79,7 +80,7 @@ TEST(Buffer, Store_Objects) {
buffer.Assign(small);
EXPECT_FALSE(buffer.IsEmpty());
EXPECT_EQ(Buffer::kContained, buffer.storage_);
- EXPECT_STREQ(typeid(Small).name(), buffer.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<Small>(), buffer.GetDataPtr()->GetTypeTag());
struct Large {
char c[20];
@@ -87,7 +88,7 @@ TEST(Buffer, Store_Objects) {
buffer.Assign(large);
EXPECT_FALSE(buffer.IsEmpty());
EXPECT_EQ(Buffer::kExternal, buffer.storage_);
- EXPECT_STREQ(typeid(Large).name(), buffer.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<Large>(), buffer.GetDataPtr()->GetTypeTag());
}
TEST(Buffer, Copy) {
@@ -98,8 +99,8 @@ TEST(Buffer, Copy) {
buffer1.CopyTo(&buffer2);
EXPECT_FALSE(buffer1.IsEmpty());
EXPECT_FALSE(buffer2.IsEmpty());
- EXPECT_STREQ(typeid(int).name(), buffer1.GetDataPtr()->GetTypeName());
- EXPECT_STREQ(typeid(int).name(), buffer2.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<int>(), buffer1.GetDataPtr()->GetTypeTag());
+ EXPECT_STREQ(GetTypeTag<int>(), buffer2.GetDataPtr()->GetTypeTag());
EXPECT_EQ(30, buffer1.GetData<int>());
EXPECT_EQ(30, buffer2.GetData<int>());
@@ -107,8 +108,8 @@ TEST(Buffer, Copy) {
buffer1.CopyTo(&buffer2);
EXPECT_FALSE(buffer1.IsEmpty());
EXPECT_FALSE(buffer2.IsEmpty());
- EXPECT_STREQ(typeid(std::string).name(), buffer1.GetDataPtr()->GetTypeName());
- EXPECT_STREQ(typeid(std::string).name(), buffer2.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<std::string>(), buffer1.GetDataPtr()->GetTypeTag());
+ EXPECT_STREQ(GetTypeTag<std::string>(), buffer2.GetDataPtr()->GetTypeTag());
EXPECT_EQ("abc", buffer1.GetData<std::string>());
EXPECT_EQ("abc", buffer2.GetData<std::string>());
}
@@ -128,7 +129,7 @@ TEST(Buffer, Move) {
// the data and any retains the actual type.
EXPECT_FALSE(buffer1.IsEmpty());
EXPECT_FALSE(buffer2.IsEmpty());
- EXPECT_STREQ(typeid(int).name(), buffer2.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<int>(), buffer2.GetDataPtr()->GetTypeTag());
EXPECT_EQ(30, buffer2.GetData<int>());
buffer1.Assign(std::string("abc"));
@@ -137,6 +138,6 @@ TEST(Buffer, Move) {
// This will make the source object effectively "Empty".
EXPECT_TRUE(buffer1.IsEmpty());
EXPECT_FALSE(buffer2.IsEmpty());
- EXPECT_STREQ(typeid(std::string).name(), buffer2.GetDataPtr()->GetTypeName());
+ EXPECT_STREQ(GetTypeTag<std::string>(), buffer2.GetDataPtr()->GetTypeTag());
EXPECT_EQ("abc", buffer2.GetData<std::string>());
}
diff --git a/brillo/any_unittest.cc b/brillo/any_unittest.cc
index 2af8845..db89884 100644
--- a/brillo/any_unittest.cc
+++ b/brillo/any_unittest.cc
@@ -305,20 +305,6 @@ TEST(Any, Compare_NonComparable) {
EXPECT_NE(person2, person3);
}
-TEST(Any, GetTypeName) {
- Any val;
- EXPECT_TRUE(val.GetTypeName().empty());
-
- val = 1;
- EXPECT_EQ(typeid(int).name(), val.GetTypeName());
-
- val = 3.1415926;
- EXPECT_EQ(typeid(double).name(), val.GetTypeName());
-
- val = std::string("blah");
- EXPECT_EQ(typeid(std::string).name(), val.GetTypeName());
-}
-
TEST(Any, GetUndecoratedTypeName) {
Any val;
EXPECT_TRUE(val.GetUndecoratedTypeName().empty());
diff --git a/brillo/dbus/exported_property_set_unittest.cc b/brillo/dbus/exported_property_set_unittest.cc
index c0deace..9233b4a 100644
--- a/brillo/dbus/exported_property_set_unittest.cc
+++ b/brillo/dbus/exported_property_set_unittest.cc
@@ -133,7 +133,7 @@ class ExportedPropertySetTest : public ::testing::Test {
void AssertMethodReturnsError(dbus::MethodCall* method_call) {
method_call->SetSerial(123);
auto response = testing::CallMethod(p_->dbus_object_, method_call);
- ASSERT_NE(dynamic_cast<dbus::ErrorResponse*>(response.get()), nullptr);
+ ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
}
std::unique_ptr<dbus::Response> GetPropertyOnInterface(
diff --git a/brillo/type_name_undecorate.cc b/brillo/type_name_undecorate.cc
index 9a1d6a1..b588170 100644
--- a/brillo/type_name_undecorate.cc
+++ b/brillo/type_name_undecorate.cc
@@ -4,6 +4,8 @@
#include <brillo/type_name_undecorate.h>
+#include <cstring>
+
#ifdef __GNUG__
#include <cstdlib>
#include <cxxabi.h>
@@ -30,4 +32,37 @@ std::string UndecorateTypeName(const char* type_name) {
#endif
}
+std::string GetUndecoratedTypeNameForTag(const char* type_tag) {
+#if defined(USE_RTTI_FOR_TYPE_TAGS) && \
+ (defined(__cpp_rtti) || defined(__GXX_RTTI))
+ return UndecorateTypeName(type_tag);
+#else
+ // The signature of type tag for, say, 'int' would be the following:
+ // const char *brillo::GetTypeTag() [T = int]
+ // So we just need to extract the type name between '[T = ' and ']'.
+ const char* token = " = ";
+ const char* pos = std::strstr(type_tag, token);
+ if (!pos)
+ return type_tag;
+ std::string name = pos + std::strlen(token);
+ if (!name.empty() && name.back() == ']')
+ name.pop_back();
+ return name;
+#endif
+}
+
+// Implementations of the explicitly instantiated GetTypeTag<T>() for common
+// types.
+template const char* GetTypeTag<int8_t>();
+template const char* GetTypeTag<uint8_t>();
+template const char* GetTypeTag<int16_t>();
+template const char* GetTypeTag<uint16_t>();
+template const char* GetTypeTag<int32_t>();
+template const char* GetTypeTag<uint32_t>();
+template const char* GetTypeTag<int64_t>();
+template const char* GetTypeTag<uint64_t>();
+template const char* GetTypeTag<bool>();
+template const char* GetTypeTag<double>();
+template const char* GetTypeTag<std::string>();
+
} // namespace brillo
diff --git a/brillo/type_name_undecorate.h b/brillo/type_name_undecorate.h
index 8cf9030..c750e58 100644
--- a/brillo/type_name_undecorate.h
+++ b/brillo/type_name_undecorate.h
@@ -10,16 +10,58 @@
#include <brillo/brillo_export.h>
+#if !defined(USE_RTTI_FOR_TYPE_TAGS) && !defined(__clang__)
+// When type information is used with RTTI disabled, we rely on
+// __PRETTY_FUNCTION__ macro for type tags. Unfortunately gcc and clang produce
+// different signatures for types that have optional template parameters, such
+// as std::vector and std::map. The problem arises when inter-operating between
+// libraries that are compiled with different compilers.
+// Since most of Brillo is compiled with clang, we choose clang here exclusively
+// and prevent this code from compiling with GCC to avoid hidden runtime errors.
+#error TypeInfo/Any with RTTI disabled is supported on clang compiler only.
+#endif
+
namespace brillo {
+template<typename T>
+const char* GetTypeTag() {
+#if defined(USE_RTTI_FOR_TYPE_TAGS) && \
+ (defined(__cpp_rtti) || defined(__GXX_RTTI))
+ return typeid(T).name();
+#else
+ // __PRETTY_FUNCTION__ would include the type T signature and therefore each
+ // instance of brillo::internal_details::GetTypeTag<T>() will have a different
+ // tag string.
+ return __PRETTY_FUNCTION__;
+#endif
+}
+
+// Explicitly instantiate GetTypeTag<T>() for common types to minimize static
+// data segment pollution.
+extern template BRILLO_EXPORT const char* GetTypeTag<int8_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<uint8_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<int16_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<uint16_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<int32_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<uint32_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<int64_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<uint64_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<bool>();
+extern template BRILLO_EXPORT const char* GetTypeTag<double>();
+extern template BRILLO_EXPORT const char* GetTypeTag<std::string>();
+
// Use brillo::UndecorateTypeName() to obtain human-readable type from
// the decorated/mangled type name returned by std::type_info::name().
BRILLO_EXPORT std::string UndecorateTypeName(const char* type_name);
+// Returns undecorated type name for the given type tag. This will extract the
+// actual type name from the type tag string.
+BRILLO_EXPORT std::string GetUndecoratedTypeNameForTag(const char* type_tag);
+
// A template helper function that returns the undecorated type name for type T.
template<typename T>
inline std::string GetUndecoratedTypeName() {
- return UndecorateTypeName(typeid(T).name());
+ return GetUndecoratedTypeNameForTag(GetTypeTag<T>());
}
} // namespace brillo
diff --git a/brillo/type_name_undecorate_unittest.cc b/brillo/type_name_undecorate_unittest.cc
new file mode 100644
index 0000000..04c1c5e
--- /dev/null
+++ b/brillo/type_name_undecorate_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <brillo/type_name_undecorate.h>
+
+#include <brillo/variant_dictionary.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+TEST(TypeTags, GetTypeTag) {
+ EXPECT_STREQ("const char *brillo::GetTypeTag() [T = int]", GetTypeTag<int>());
+ EXPECT_STREQ("const char *brillo::GetTypeTag() [T = std::__1::map<std::__1::"
+ "basic_string<char, std::__1::char_traits<char>, "
+ "std::__1::allocator<char> >, brillo::Any, std::__1::less<"
+ "std::__1::basic_string<char, std::__1::char_traits<char>, "
+ "std::__1::allocator<char> > >, std::__1::allocator<std::__1::"
+ "pair<const std::__1::basic_string<char, std::__1::char_traits"
+ "<char>, std::__1::allocator<char> >, brillo::Any> > >]",
+ GetTypeTag<VariantDictionary>());
+ EXPECT_STREQ("const char *brillo::GetTypeTag() [T = int []]",
+ GetTypeTag<int[]>());
+}
+
+TEST(TypeDecoration, UndecorateTypeName) {
+ EXPECT_EQ("int", UndecorateTypeName("i"));
+ EXPECT_EQ("char const* brillo::GetTypeTag<unsigned long long>()",
+ UndecorateTypeName("_ZN6brillo10GetTypeTagIyEEPKcv"));
+ EXPECT_EQ("std::__1::to_string(int)",
+ UndecorateTypeName("_ZNSt3__19to_stringEi"));
+}
+
+TEST(TypeDecoration, GetUndecoratedTypeNameForTag) {
+ EXPECT_EQ("int",
+ GetUndecoratedTypeNameForTag(
+ "const char *brillo::GetTypeTag() [T = int]"));
+ EXPECT_EQ("int []",
+ GetUndecoratedTypeNameForTag(
+ "const char *brillo::GetTypeTag() [T = int []]"));
+ EXPECT_EQ("foo::bar<int []>()",
+ GetUndecoratedTypeNameForTag(
+ "const char *brillo::GetTypeTag() [T = foo::bar<int []>()]"));
+}
+
+TEST(TypeDecoration, GetUndecoratedTypeName) {
+ EXPECT_EQ("int", GetUndecoratedTypeName<int>());
+ EXPECT_EQ("int *", GetUndecoratedTypeName<int*>());
+ EXPECT_EQ("const int *", GetUndecoratedTypeName<const int*>());
+ EXPECT_EQ("int []", GetUndecoratedTypeName<int[]>());
+ EXPECT_EQ("bool", GetUndecoratedTypeName<bool>());
+ EXPECT_EQ("char", GetUndecoratedTypeName<char>());
+ EXPECT_EQ("float", GetUndecoratedTypeName<float>());
+ EXPECT_EQ("double", GetUndecoratedTypeName<double>());
+ EXPECT_EQ("long", GetUndecoratedTypeName<long>());
+ EXPECT_EQ("std::__1::map<int, double, std::__1::less<int>, "
+ "std::__1::allocator<std::__1::pair<const int, double> > >",
+ (GetUndecoratedTypeName<std::map<int, double>>()));
+}
+
+} // namespace brillo