xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/TypeName.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- TypeName.h -----------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_SUPPORT_TYPENAME_H
10 #define LLVM_SUPPORT_TYPENAME_H
11 
12 #include <string_view>
13 
14 #include "llvm/ADT/StringRef.h"
15 
16 // Versions of GCC prior to GCC 9 don't declare __PRETTY_FUNCTION__ as constexpr
17 #if defined(__clang__) || defined(_MSC_VER) ||                                 \
18     (defined(__GNUC__) && __GNUC__ >= 9)
19 #define LLVM_GET_TYPE_NAME_CONSTEXPR constexpr
20 #define LLVM_GET_TYPE_NAME_STATIC_ASSERT 1
21 #else
22 #define LLVM_GET_TYPE_NAME_CONSTEXPR
23 #define LLVM_GET_TYPE_NAME_STATIC_ASSERT 0
24 #include <cassert>
25 #endif
26 
27 namespace llvm {
28 
29 /// We provide a function which tries to compute the (demangled) name of a type
30 /// statically.
31 ///
32 /// This routine may fail on some platforms or for particularly unusual types.
33 /// Do not use it for anything other than logging and debugging aids. It isn't
34 /// portable or dependendable in any real sense.
35 ///
36 /// The returned StringRef will point into a static storage duration string.
37 /// However, it may not be null terminated and may be some strangely aligned
38 /// inner substring of a larger string.
39 template <typename DesiredTypeName>
getTypeName()40 inline LLVM_GET_TYPE_NAME_CONSTEXPR StringRef getTypeName() {
41 #if defined(__clang__) || defined(__GNUC__)
42   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view Name = __PRETTY_FUNCTION__;
43 
44   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view Key = "DesiredTypeName = ";
45   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view TemplateParamsStart =
46       Name.substr(Name.find(Key));
47 #if LLVM_GET_TYPE_NAME_STATIC_ASSERT
48   static_assert(!TemplateParamsStart.empty(),
49                 "Unable to find the template parameter!");
50 #else
51   assert(!TemplateParamsStart.empty() &&
52          "Unable to find the template parameter!");
53 #endif
54 
55   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view SubstitutionKey =
56       TemplateParamsStart.substr(Key.size());
57 
58 #if LLVM_GET_TYPE_NAME_STATIC_ASSERT
59   // ends_with() is only available in c++20
60   static_assert(!SubstitutionKey.empty() && SubstitutionKey.back() == ']',
61                 "Name doesn't end in the substitution key!");
62 #else
63   assert(!SubstitutionKey.empty() && SubstitutionKey.back() == ']' &&
64          "Name doesn't end in the substitution key!");
65 #endif
66 
67   return SubstitutionKey.substr(0, SubstitutionKey.size() - 1);
68 #elif defined(_MSC_VER)
69   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view Name = __FUNCSIG__;
70 
71   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view Key = "getTypeName<";
72   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view GetTypeNameStart =
73       Name.substr(Name.find(Key));
74   static_assert(!GetTypeNameStart.empty(),
75                 "Unable to find the template parameter!");
76   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view SubstitutionKey =
77       GetTypeNameStart.substr(Key.size());
78 
79   // starts_with() only available in c++20
80   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view RmPrefixClass =
81       SubstitutionKey.find("class ") == 0
82           ? SubstitutionKey.substr(sizeof("class ") - 1)
83           : SubstitutionKey;
84   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view RmPrefixStruct =
85       RmPrefixClass.find("struct ") == 0
86           ? RmPrefixClass.substr(sizeof("struct ") - 1)
87           : RmPrefixClass;
88   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view RmPrefixUnion =
89       RmPrefixStruct.find("union ") == 0
90           ? RmPrefixStruct.substr(sizeof("union ") - 1)
91           : RmPrefixStruct;
92   LLVM_GET_TYPE_NAME_CONSTEXPR std::string_view RmPrefixEnum =
93       RmPrefixUnion.find("enum ") == 0
94           ? RmPrefixUnion.substr(sizeof("enum ") - 1)
95           : RmPrefixUnion;
96 
97   LLVM_GET_TYPE_NAME_CONSTEXPR auto AnglePos = RmPrefixEnum.rfind('>');
98   static_assert(AnglePos != std::string_view::npos,
99                 "Unable to find the closing '>'!");
100   return RmPrefixEnum.substr(0, AnglePos);
101 #else
102   // No known technique for statically extracting a type name on this compiler.
103   // We return a string that is unlikely to look like any type in LLVM.
104   return "UNKNOWN_TYPE";
105 #endif
106 }
107 
108 } // namespace llvm
109 
110 // Don't leak out of this header file
111 #undef LLVM_GET_TYPE_NAME_CONSTEXPR
112 #undef LLVM_GET_TYPE_NAME_STATIC_ASSERT
113 
114 #endif
115