aboutsummaryrefslogtreecommitdiffstats
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
parent2fd46ba1458275cd16b0949675bff70cc8abcdad (diff)
downloadplatform_external_libbrillo-4d8501c1f9689c833d38c9087df28b971a6ebe42.tar.gz
platform_external_libbrillo-4d8501c1f9689c833d38c9087df28b971a6ebe42.tar.bz2
platform_external_libbrillo-4d8501c1f9689c833d38c9087df28b971a6ebe42.zip
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
-rw-r--r--Android.mk16
-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
-rw-r--r--libbrillo.gypi1
11 files changed, 175 insertions, 65 deletions
diff --git a/Android.mk b/Android.mk
index 2819b1c..2181a3a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -122,6 +122,7 @@ libbrillo_test_sources := \
brillo/streams/stream_unittest.cc \
brillo/streams/stream_utils_unittest.cc \
brillo/strings/string_utils_unittest.cc \
+ brillo/type_name_undecorate_unittest.cc \
brillo/unittest_utils.cc \
brillo/url_utils_unittest.cc \
@@ -159,7 +160,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries)
LOCAL_STATIC_LIBRARIES := libmodpb64
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
@@ -175,7 +175,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) \
libbinder libutils
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
@@ -193,7 +192,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
libchrome-dbus libdbus
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) external/dbus
include $(BUILD_SHARED_LIBRARY)
@@ -212,7 +210,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
libminijail
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
@@ -228,7 +225,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
libcrypto libssl
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
@@ -244,7 +240,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
libbrillo-stream libcurl
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
@@ -259,7 +254,6 @@ LOCAL_C_INCLUDES := $(libbrillo_includes)
LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries)
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
@@ -276,7 +270,6 @@ LOCAL_STATIC_LIBRARIES := libmodpb64
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
LOCAL_CLANG := true
-LOCAL_RTTI_FLAG := -frtti
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_STATIC_LIBRARY)
@@ -293,7 +286,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo libcurl \
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -Wno-sign-compare
LOCAL_CLANG := true
-LOCAL_RTTI_FLAG := -frtti
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_STATIC_LIBRARY)
@@ -308,7 +300,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries)
LOCAL_STATIC_LIBRARIES := libmodpb64-host
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_HOST_SHARED_LIBRARY)
@@ -326,7 +317,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
libcrypto-host libssl-host
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_HOST_SHARED_LIBRARY)
@@ -342,7 +332,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
libbrillo-stream libcurl-host
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_HOST_SHARED_LIBRARY)
@@ -366,7 +355,7 @@ LOCAL_C_INCLUDES := \
LOCAL_STATIC_LIBRARIES := libgtest libchrome_test_helpers \
libbrillo-test-helpers libgmock libBionicGtestMain
LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo libcurl \
- libbrillo-http libbrillo-stream libcrypto libprotobuf-cpp-lite-rtti
+ libbrillo-http libbrillo-stream libcrypto libprotobuf-cpp-lite
ifeq ($(BRILLO_USE_DBUS),1)
LOCAL_SRC_FILES += $(libbrillo_dbus_test_sources)
LOCAL_STATIC_LIBRARIES += libchrome_dbus_test_helpers
@@ -375,7 +364,6 @@ endif # BRILLO_USE_DBUS == 1
LOCAL_CFLAGS := $(libbrillo_CFLAGS)
LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -Wno-sign-compare
LOCAL_CLANG := true
-LOCAL_RTTI_FLAG := -frtti
include $(BUILD_NATIVE_TEST)
# Run unit tests on target
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
diff --git a/libbrillo.gypi b/libbrillo.gypi
index 6dec2e4..d39290f 100644
--- a/libbrillo.gypi
+++ b/libbrillo.gypi
@@ -353,6 +353,7 @@
'brillo/streams/stream_unittest.cc',
'brillo/streams/stream_utils_unittest.cc',
'brillo/strings/string_utils_unittest.cc',
+ 'brillo/type_name_undecorate_unittest.cc',
'brillo/unittest_utils.cc',
'brillo/url_utils_unittest.cc',
'brillo/variant_dictionary_unittest.cc',