Index: include/llvm/Support/TypeName.h =================================================================== --- /dev/null +++ include/llvm/Support/TypeName.h @@ -0,0 +1,62 @@ +//===- TypeName.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TYPENAME_H +#define LLVM_SUPPORT_TYPENAME_H + +#include "llvm/ADT/StringRef.h" +#include + +#ifdef _MSC_VER +// We use typeinfo below which MSVC supports in restricted circumstances even +// when RTTI is disabled. +#include +#endif + +namespace llvm { + +/// We provide a function which tries to compute the (demangled) name of a type +/// statically. +/// +/// This routine may fail on some platforms or for particularly unusual types. +/// Do not use it for anything other than logging and debugging aids. It isn't +/// portable or dependendable in any real sense. +/// +/// The returned const char * will point to a static storage duration C-string. +template +inline StringRef getTypeName() { +#if defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER) + StringRef Name = __PRETTY_FUNCTION__; + StringRef Key = "DesiredTypeName = "; + Name = Name.substr(Name.find(Key)); + if (Name.empty() || !Name.endswith("]")) + return "UNKNOWN_TYPE"; + + return Name.drop_front(Key.size()).drop_back(1); +#elif defined(_MSC_VER) + StringRef Name = typeid(T).name(); + if (Name.startswith("struct ")) + return Name.substr(strlen("struct ")); + if (Name.startswith("class ")) + return Name.substr(strlen("class ")); + if (Name.startswith("union ")) + return Name.substr(strlen("union ")); + + // Otherwise, this is likely a mangled name which is better than nothing. + return Name; +#else + // No known technique for statically extracting a type name on this compiler. + // We return a string that is unlikely to look like any type in LLVM. + return "UNKNOWN_TYPE"; +#endif +} + +} + +#endif Index: unittests/Support/CMakeLists.txt =================================================================== --- unittests/Support/CMakeLists.txt +++ unittests/Support/CMakeLists.txt @@ -42,6 +42,7 @@ ThreadPool.cpp TimerTest.cpp TimeValueTest.cpp + TypeNameTest.cpp TrailingObjectsTest.cpp UnicodeTest.cpp YAMLIOTest.cpp Index: unittests/Support/TypeNameTest.cpp =================================================================== --- /dev/null +++ unittests/Support/TypeNameTest.cpp @@ -0,0 +1,49 @@ +//===- TypeNameTest.cpp ---------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/TypeName.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { +namespace N1 { +struct S1 {}; +class C1 {}; +union U1 {}; +} + +TEST(TypeNameTest, Names) { + struct S2 {}; + + StringRef S1Name = getTypeName(); + StringRef C1Name = getTypeName(); + StringRef U1Name = getTypeName(); + StringRef S2Name = getTypeName(); + +#if defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER) || \ + defined(_MSC_VER) + EXPECT_TRUE(S1Name.endswith("::N1::S1")) << S1Name.str(); + EXPECT_TRUE(C1Name.endswith("::N1::C1")) << C1Name.str(); + EXPECT_TRUE(U1Name.endswith("::N1::U1")) << U1Name.str(); +#ifdef __clang__ + EXPECT_TRUE(S2Name.endswith("S2")) << S2Name.str(); +#else + EXPECT_TRUE(S2Name.endswith("::S2")) << S2Name.str(); +#endif +#else + EXPECT_EQ("UNKNOWN_TYPE", S1Name); + EXPECT_EQ("UNKNOWN_TYPE", C1Name); + EXPECT_EQ("UNKNOWN_TYPE", U1Name); + EXPECT_EQ("UNKNOWN_TYPE", S2Name); +#endif +} + +} // end anonymous namespace