Index: llvm/trunk/include/llvm/Support/TypeName.h =================================================================== --- llvm/trunk/include/llvm/Support/TypeName.h +++ llvm/trunk/include/llvm/Support/TypeName.h @@ -0,0 +1,65 @@ +//===- 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" + +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 StringRef will point into a static storage duration string. +/// However, it may not be null terminated and may be some strangely aligned +/// inner substring of a larger 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)); + assert(!Name.empty() && "Unable to find the template parameter!"); + Name = Name.drop_front(Key.size()); + + assert(Name.endswith("]") && "Name doesn't end in the substitution key!"); + return Name.drop_back(1); +#elif defined(_MSC_VER) + StringRef Name = __FUNCSIG__; + + StringRef Key = "getTypeName<"; + Name = Name.substr(Name.find(Key)); + assert(!Name.empty() && "Unable to find the function name!"); + Name = Name.drop_front(Key.size()); + + for (StringRef Prefix : {"class ", "struct ", "union ", "enum "}) + if (Name.startswith(Prefix)) { + Name = Name.drop_front(Prefix.size()); + break; + } + + auto AnglePos = Name.rfind('>'); + assert(AnglePos != StringRef::npos && "Unable to find the closing '>'!"); + return Name.substr(0, AnglePos); +#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: llvm/trunk/unittests/Support/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/Support/CMakeLists.txt +++ llvm/trunk/unittests/Support/CMakeLists.txt @@ -42,6 +42,7 @@ ThreadPool.cpp TimerTest.cpp TimeValueTest.cpp + TypeNameTest.cpp TrailingObjectsTest.cpp UnicodeTest.cpp YAMLIOTest.cpp Index: llvm/trunk/unittests/Support/TypeNameTest.cpp =================================================================== --- llvm/trunk/unittests/Support/TypeNameTest.cpp +++ llvm/trunk/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