File: | llvm/lib/Demangle/MicrosoftDemangleNodes.cpp |
Warning: | line 123, column 3 Potential leak of memory pointed to by 'OS.Buffer' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- MicrosoftDemangle.cpp ----------------------------------------------===// | |||
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 | // This file defines a demangler for MSVC-style mangled symbols. | |||
10 | // | |||
11 | //===----------------------------------------------------------------------===// | |||
12 | ||||
13 | #include "llvm/Demangle/MicrosoftDemangleNodes.h" | |||
14 | #include "llvm/Demangle/DemangleConfig.h" | |||
15 | #include "llvm/Demangle/Utility.h" | |||
16 | #include <cctype> | |||
17 | #include <string> | |||
18 | ||||
19 | using namespace llvm; | |||
20 | using namespace ms_demangle; | |||
21 | ||||
22 | #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc)case Enum::Value: OS << Desc; break; \ | |||
23 | case Enum::Value: \ | |||
24 | OS << Desc; \ | |||
25 | break; | |||
26 | ||||
27 | // Writes a space if the last token does not end with a punctuation. | |||
28 | static void outputSpaceIfNecessary(OutputStream &OS) { | |||
29 | if (OS.empty()) | |||
30 | return; | |||
31 | ||||
32 | char C = OS.back(); | |||
33 | if (std::isalnum(C) || C == '>') | |||
34 | OS << " "; | |||
35 | } | |||
36 | ||||
37 | static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) { | |||
38 | switch (Q) { | |||
39 | case Q_Const: | |||
40 | OS << "const"; | |||
41 | break; | |||
42 | case Q_Volatile: | |||
43 | OS << "volatile"; | |||
44 | break; | |||
45 | case Q_Restrict: | |||
46 | OS << "__restrict"; | |||
47 | break; | |||
48 | default: | |||
49 | break; | |||
50 | } | |||
51 | } | |||
52 | ||||
53 | static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q, | |||
54 | Qualifiers Mask, bool NeedSpace) { | |||
55 | if (!(Q & Mask)) | |||
56 | return NeedSpace; | |||
57 | ||||
58 | if (NeedSpace) | |||
59 | OS << " "; | |||
60 | ||||
61 | outputSingleQualifier(OS, Mask); | |||
62 | return true; | |||
63 | } | |||
64 | ||||
65 | static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore, | |||
66 | bool SpaceAfter) { | |||
67 | if (Q == Q_None) | |||
68 | return; | |||
69 | ||||
70 | size_t Pos1 = OS.getCurrentPosition(); | |||
71 | SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore); | |||
72 | SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore); | |||
73 | SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore); | |||
74 | size_t Pos2 = OS.getCurrentPosition(); | |||
75 | if (SpaceAfter && Pos2 > Pos1) | |||
76 | OS << " "; | |||
77 | } | |||
78 | ||||
79 | static void outputCallingConvention(OutputStream &OS, CallingConv CC) { | |||
80 | outputSpaceIfNecessary(OS); | |||
81 | ||||
82 | switch (CC) { | |||
83 | case CallingConv::Cdecl: | |||
84 | OS << "__cdecl"; | |||
85 | break; | |||
86 | case CallingConv::Fastcall: | |||
87 | OS << "__fastcall"; | |||
88 | break; | |||
89 | case CallingConv::Pascal: | |||
90 | OS << "__pascal"; | |||
91 | break; | |||
92 | case CallingConv::Regcall: | |||
93 | OS << "__regcall"; | |||
94 | break; | |||
95 | case CallingConv::Stdcall: | |||
96 | OS << "__stdcall"; | |||
97 | break; | |||
98 | case CallingConv::Thiscall: | |||
99 | OS << "__thiscall"; | |||
100 | break; | |||
101 | case CallingConv::Eabi: | |||
102 | OS << "__eabi"; | |||
103 | break; | |||
104 | case CallingConv::Vectorcall: | |||
105 | OS << "__vectorcall"; | |||
106 | break; | |||
107 | case CallingConv::Clrcall: | |||
108 | OS << "__clrcall"; | |||
109 | break; | |||
110 | case CallingConv::Swift: | |||
111 | OS << "__attribute__((__swiftcall__)) "; | |||
112 | break; | |||
113 | default: | |||
114 | break; | |||
115 | } | |||
116 | } | |||
117 | ||||
118 | std::string Node::toString(OutputFlags Flags) const { | |||
119 | OutputStream OS; | |||
120 | initializeOutputStream(nullptr, nullptr, OS, 1024); | |||
121 | this->output(OS, Flags); | |||
122 | OS << '\0'; | |||
| ||||
123 | return {OS.getBuffer()}; | |||
| ||||
124 | } | |||
125 | ||||
126 | void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | |||
127 | switch (PrimKind) { | |||
128 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void")case PrimitiveKind::Void: OS << "void"; break;; | |||
129 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool")case PrimitiveKind::Bool: OS << "bool"; break;; | |||
130 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char")case PrimitiveKind::Char: OS << "char"; break;; | |||
131 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char")case PrimitiveKind::Schar: OS << "signed char"; break;; | |||
132 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char")case PrimitiveKind::Uchar: OS << "unsigned char"; break ;; | |||
133 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t")case PrimitiveKind::Char8: OS << "char8_t"; break;; | |||
134 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t")case PrimitiveKind::Char16: OS << "char16_t"; break;; | |||
135 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t")case PrimitiveKind::Char32: OS << "char32_t"; break;; | |||
136 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short")case PrimitiveKind::Short: OS << "short"; break;; | |||
137 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short")case PrimitiveKind::Ushort: OS << "unsigned short"; break ;; | |||
138 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int")case PrimitiveKind::Int: OS << "int"; break;; | |||
139 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int")case PrimitiveKind::Uint: OS << "unsigned int"; break;; | |||
140 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long")case PrimitiveKind::Long: OS << "long"; break;; | |||
141 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long")case PrimitiveKind::Ulong: OS << "unsigned long"; break ;; | |||
142 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64")case PrimitiveKind::Int64: OS << "__int64"; break;; | |||
143 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64")case PrimitiveKind::Uint64: OS << "unsigned __int64"; break ;; | |||
144 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t")case PrimitiveKind::Wchar: OS << "wchar_t"; break;; | |||
145 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float")case PrimitiveKind::Float: OS << "float"; break;; | |||
146 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double")case PrimitiveKind::Double: OS << "double"; break;; | |||
147 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double")case PrimitiveKind::Ldouble: OS << "long double"; break ;; | |||
148 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t")case PrimitiveKind::Nullptr: OS << "std::nullptr_t"; break ;; | |||
149 | } | |||
150 | outputQualifiers(OS, Quals, true, false); | |||
151 | } | |||
152 | ||||
153 | void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const { | |||
154 | output(OS, Flags, ", "); | |||
155 | } | |||
156 | ||||
157 | void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags, | |||
158 | StringView Separator) const { | |||
159 | if (Count == 0) | |||
160 | return; | |||
161 | if (Nodes[0]) | |||
162 | Nodes[0]->output(OS, Flags); | |||
163 | for (size_t I = 1; I < Count; ++I) { | |||
164 | OS << Separator; | |||
165 | Nodes[I]->output(OS, Flags); | |||
166 | } | |||
167 | } | |||
168 | ||||
169 | void EncodedStringLiteralNode::output(OutputStream &OS, | |||
170 | OutputFlags Flags) const { | |||
171 | switch (Char) { | |||
172 | case CharKind::Wchar: | |||
173 | OS << "L\""; | |||
174 | break; | |||
175 | case CharKind::Char: | |||
176 | OS << "\""; | |||
177 | break; | |||
178 | case CharKind::Char16: | |||
179 | OS << "u\""; | |||
180 | break; | |||
181 | case CharKind::Char32: | |||
182 | OS << "U\""; | |||
183 | break; | |||
184 | } | |||
185 | OS << DecodedString << "\""; | |||
186 | if (IsTruncated) | |||
187 | OS << "..."; | |||
188 | } | |||
189 | ||||
190 | void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const { | |||
191 | if (IsNegative) | |||
192 | OS << '-'; | |||
193 | OS << Value; | |||
194 | } | |||
195 | ||||
196 | void TemplateParameterReferenceNode::output(OutputStream &OS, | |||
197 | OutputFlags Flags) const { | |||
198 | if (ThunkOffsetCount > 0) | |||
199 | OS << "{"; | |||
200 | else if (Affinity == PointerAffinity::Pointer) | |||
201 | OS << "&"; | |||
202 | ||||
203 | if (Symbol) { | |||
204 | Symbol->output(OS, Flags); | |||
205 | if (ThunkOffsetCount > 0) | |||
206 | OS << ", "; | |||
207 | } | |||
208 | ||||
209 | if (ThunkOffsetCount > 0) | |||
210 | OS << ThunkOffsets[0]; | |||
211 | for (int I = 1; I < ThunkOffsetCount; ++I) { | |||
212 | OS << ", " << ThunkOffsets[I]; | |||
213 | } | |||
214 | if (ThunkOffsetCount > 0) | |||
215 | OS << "}"; | |||
216 | } | |||
217 | ||||
218 | void IdentifierNode::outputTemplateParameters(OutputStream &OS, | |||
219 | OutputFlags Flags) const { | |||
220 | if (!TemplateParams) | |||
221 | return; | |||
222 | OS << "<"; | |||
223 | TemplateParams->output(OS, Flags); | |||
224 | OS << ">"; | |||
225 | } | |||
226 | ||||
227 | void DynamicStructorIdentifierNode::output(OutputStream &OS, | |||
228 | OutputFlags Flags) const { | |||
229 | if (IsDestructor) | |||
230 | OS << "`dynamic atexit destructor for "; | |||
231 | else | |||
232 | OS << "`dynamic initializer for "; | |||
233 | ||||
234 | if (Variable) { | |||
235 | OS << "`"; | |||
236 | Variable->output(OS, Flags); | |||
237 | OS << "''"; | |||
238 | } else { | |||
239 | OS << "'"; | |||
240 | Name->output(OS, Flags); | |||
241 | OS << "''"; | |||
242 | } | |||
243 | } | |||
244 | ||||
245 | void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { | |||
246 | OS << Name; | |||
247 | outputTemplateParameters(OS, Flags); | |||
248 | } | |||
249 | ||||
250 | void IntrinsicFunctionIdentifierNode::output(OutputStream &OS, | |||
251 | OutputFlags Flags) const { | |||
252 | switch (Operator) { | |||
253 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new")case IntrinsicFunctionKind::New: OS << "operator new"; break ;; | |||
254 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete")case IntrinsicFunctionKind::Delete: OS << "operator delete" ; break;; | |||
255 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=")case IntrinsicFunctionKind::Assign: OS << "operator="; break ;; | |||
256 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>")case IntrinsicFunctionKind::RightShift: OS << "operator>>" ; break;; | |||
257 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<")case IntrinsicFunctionKind::LeftShift: OS << "operator<<" ; break;; | |||
258 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!")case IntrinsicFunctionKind::LogicalNot: OS << "operator!" ; break;; | |||
259 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==")case IntrinsicFunctionKind::Equals: OS << "operator=="; break;; | |||
260 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=")case IntrinsicFunctionKind::NotEquals: OS << "operator!=" ; break;; | |||
261 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,case IntrinsicFunctionKind::ArraySubscript: OS << "operator[]" ; break; | |||
262 | "operator[]")case IntrinsicFunctionKind::ArraySubscript: OS << "operator[]" ; break;; | |||
263 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->")case IntrinsicFunctionKind::Pointer: OS << "operator->" ; break;; | |||
264 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++")case IntrinsicFunctionKind::Increment: OS << "operator++" ; break;; | |||
265 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--")case IntrinsicFunctionKind::Decrement: OS << "operator--" ; break;; | |||
266 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-")case IntrinsicFunctionKind::Minus: OS << "operator-"; break ;; | |||
267 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+")case IntrinsicFunctionKind::Plus: OS << "operator+"; break ;; | |||
268 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*")case IntrinsicFunctionKind::Dereference: OS << "operator*" ; break;; | |||
269 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&")case IntrinsicFunctionKind::BitwiseAnd: OS << "operator&" ; break;; | |||
270 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,case IntrinsicFunctionKind::MemberPointer: OS << "operator->*" ; break; | |||
271 | "operator->*")case IntrinsicFunctionKind::MemberPointer: OS << "operator->*" ; break;; | |||
272 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/")case IntrinsicFunctionKind::Divide: OS << "operator/"; break ;; | |||
273 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%")case IntrinsicFunctionKind::Modulus: OS << "operator%"; break;; | |||
274 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<")case IntrinsicFunctionKind::LessThan: OS << "operator<" ; break;; | |||
275 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=")case IntrinsicFunctionKind::LessThanEqual: OS << "operator<=" ; break;; | |||
276 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>")case IntrinsicFunctionKind::GreaterThan: OS << "operator>" ; break;; | |||
277 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,case IntrinsicFunctionKind::GreaterThanEqual: OS << "operator>=" ; break; | |||
278 | "operator>=")case IntrinsicFunctionKind::GreaterThanEqual: OS << "operator>=" ; break;; | |||
279 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,")case IntrinsicFunctionKind::Comma: OS << "operator,"; break ;; | |||
280 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()")case IntrinsicFunctionKind::Parens: OS << "operator()"; break;; | |||
281 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~")case IntrinsicFunctionKind::BitwiseNot: OS << "operator~" ; break;; | |||
282 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^")case IntrinsicFunctionKind::BitwiseXor: OS << "operator^" ; break;; | |||
283 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|")case IntrinsicFunctionKind::BitwiseOr: OS << "operator|" ; break;; | |||
284 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&")case IntrinsicFunctionKind::LogicalAnd: OS << "operator&&" ; break;; | |||
285 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||")case IntrinsicFunctionKind::LogicalOr: OS << "operator||" ; break;; | |||
286 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=")case IntrinsicFunctionKind::TimesEqual: OS << "operator*=" ; break;; | |||
287 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=")case IntrinsicFunctionKind::PlusEqual: OS << "operator+=" ; break;; | |||
288 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=")case IntrinsicFunctionKind::MinusEqual: OS << "operator-=" ; break;; | |||
289 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=")case IntrinsicFunctionKind::DivEqual: OS << "operator/=" ; break;; | |||
290 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=")case IntrinsicFunctionKind::ModEqual: OS << "operator%=" ; break;; | |||
291 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=")case IntrinsicFunctionKind::RshEqual: OS << "operator>>=" ; break;; | |||
292 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=")case IntrinsicFunctionKind::LshEqual: OS << "operator<<=" ; break;; | |||
293 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,case IntrinsicFunctionKind::BitwiseAndEqual: OS << "operator&=" ; break; | |||
294 | "operator&=")case IntrinsicFunctionKind::BitwiseAndEqual: OS << "operator&=" ; break;; | |||
295 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,case IntrinsicFunctionKind::BitwiseOrEqual: OS << "operator|=" ; break; | |||
296 | "operator|=")case IntrinsicFunctionKind::BitwiseOrEqual: OS << "operator|=" ; break;; | |||
297 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,case IntrinsicFunctionKind::BitwiseXorEqual: OS << "operator^=" ; break; | |||
298 | "operator^=")case IntrinsicFunctionKind::BitwiseXorEqual: OS << "operator^=" ; break;; | |||
299 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'")case IntrinsicFunctionKind::VbaseDtor: OS << "`vbase dtor'" ; break;; | |||
300 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,case IntrinsicFunctionKind::VecDelDtor: OS << "`vector deleting dtor'" ; break; | |||
301 | "`vector deleting dtor'")case IntrinsicFunctionKind::VecDelDtor: OS << "`vector deleting dtor'" ; break;; | |||
302 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,case IntrinsicFunctionKind::DefaultCtorClosure: OS << "`default ctor closure'" ; break; | |||
303 | "`default ctor closure'")case IntrinsicFunctionKind::DefaultCtorClosure: OS << "`default ctor closure'" ; break;; | |||
304 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,case IntrinsicFunctionKind::ScalarDelDtor: OS << "`scalar deleting dtor'" ; break; | |||
305 | "`scalar deleting dtor'")case IntrinsicFunctionKind::ScalarDelDtor: OS << "`scalar deleting dtor'" ; break;; | |||
306 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,case IntrinsicFunctionKind::VecCtorIter: OS << "`vector ctor iterator'" ; break; | |||
307 | "`vector ctor iterator'")case IntrinsicFunctionKind::VecCtorIter: OS << "`vector ctor iterator'" ; break;; | |||
308 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,case IntrinsicFunctionKind::VecDtorIter: OS << "`vector dtor iterator'" ; break; | |||
309 | "`vector dtor iterator'")case IntrinsicFunctionKind::VecDtorIter: OS << "`vector dtor iterator'" ; break;; | |||
310 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,case IntrinsicFunctionKind::VecVbaseCtorIter: OS << "`vector vbase ctor iterator'" ; break; | |||
311 | "`vector vbase ctor iterator'")case IntrinsicFunctionKind::VecVbaseCtorIter: OS << "`vector vbase ctor iterator'" ; break;; | |||
312 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,case IntrinsicFunctionKind::VdispMap: OS << "`virtual displacement map'" ; break; | |||
313 | "`virtual displacement map'")case IntrinsicFunctionKind::VdispMap: OS << "`virtual displacement map'" ; break;; | |||
314 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,case IntrinsicFunctionKind::EHVecCtorIter: OS << "`eh vector ctor iterator'" ; break; | |||
315 | "`eh vector ctor iterator'")case IntrinsicFunctionKind::EHVecCtorIter: OS << "`eh vector ctor iterator'" ; break;; | |||
316 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,case IntrinsicFunctionKind::EHVecDtorIter: OS << "`eh vector dtor iterator'" ; break; | |||
317 | "`eh vector dtor iterator'")case IntrinsicFunctionKind::EHVecDtorIter: OS << "`eh vector dtor iterator'" ; break;; | |||
318 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,case IntrinsicFunctionKind::EHVecVbaseCtorIter: OS << "`eh vector vbase ctor iterator'" ; break; | |||
319 | "`eh vector vbase ctor iterator'")case IntrinsicFunctionKind::EHVecVbaseCtorIter: OS << "`eh vector vbase ctor iterator'" ; break;; | |||
320 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,case IntrinsicFunctionKind::CopyCtorClosure: OS << "`copy ctor closure'" ; break; | |||
321 | "`copy ctor closure'")case IntrinsicFunctionKind::CopyCtorClosure: OS << "`copy ctor closure'" ; break;; | |||
322 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,case IntrinsicFunctionKind::LocalVftableCtorClosure: OS << "`local vftable ctor closure'"; break; | |||
323 | "`local vftable ctor closure'")case IntrinsicFunctionKind::LocalVftableCtorClosure: OS << "`local vftable ctor closure'"; break;; | |||
324 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]")case IntrinsicFunctionKind::ArrayNew: OS << "operator new[]" ; break;; | |||
325 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,case IntrinsicFunctionKind::ArrayDelete: OS << "operator delete[]" ; break; | |||
326 | "operator delete[]")case IntrinsicFunctionKind::ArrayDelete: OS << "operator delete[]" ; break;; | |||
327 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,case IntrinsicFunctionKind::ManVectorCtorIter: OS << "`managed vector ctor iterator'" ; break; | |||
328 | "`managed vector ctor iterator'")case IntrinsicFunctionKind::ManVectorCtorIter: OS << "`managed vector ctor iterator'" ; break;; | |||
329 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,case IntrinsicFunctionKind::ManVectorDtorIter: OS << "`managed vector dtor iterator'" ; break; | |||
330 | "`managed vector dtor iterator'")case IntrinsicFunctionKind::ManVectorDtorIter: OS << "`managed vector dtor iterator'" ; break;; | |||
331 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,case IntrinsicFunctionKind::EHVectorCopyCtorIter: OS << "`EH vector copy ctor iterator'"; break; | |||
332 | "`EH vector copy ctor iterator'")case IntrinsicFunctionKind::EHVectorCopyCtorIter: OS << "`EH vector copy ctor iterator'"; break;; | |||
333 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,case IntrinsicFunctionKind::EHVectorVbaseCopyCtorIter: OS << "`EH vector vbase copy ctor iterator'"; break; | |||
334 | "`EH vector vbase copy ctor iterator'")case IntrinsicFunctionKind::EHVectorVbaseCopyCtorIter: OS << "`EH vector vbase copy ctor iterator'"; break;; | |||
335 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,case IntrinsicFunctionKind::VectorCopyCtorIter: OS << "`vector copy ctor iterator'" ; break; | |||
336 | "`vector copy ctor iterator'")case IntrinsicFunctionKind::VectorCopyCtorIter: OS << "`vector copy ctor iterator'" ; break;; | |||
337 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,case IntrinsicFunctionKind::VectorVbaseCopyCtorIter: OS << "`vector vbase copy constructor iterator'"; break; | |||
338 | "`vector vbase copy constructor iterator'")case IntrinsicFunctionKind::VectorVbaseCopyCtorIter: OS << "`vector vbase copy constructor iterator'"; break;; | |||
339 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,case IntrinsicFunctionKind::ManVectorVbaseCopyCtorIter: OS << "`managed vector vbase copy constructor iterator'"; break; | |||
340 | "`managed vector vbase copy constructor iterator'")case IntrinsicFunctionKind::ManVectorVbaseCopyCtorIter: OS << "`managed vector vbase copy constructor iterator'"; break;; | |||
341 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait,case IntrinsicFunctionKind::CoAwait: OS << "operator co_await" ; break; | |||
342 | "operator co_await")case IntrinsicFunctionKind::CoAwait: OS << "operator co_await" ; break;; | |||
343 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>")case IntrinsicFunctionKind::Spaceship: OS << "operator<=>" ; break;; | |||
344 | case IntrinsicFunctionKind::MaxIntrinsic: | |||
345 | case IntrinsicFunctionKind::None: | |||
346 | break; | |||
347 | } | |||
348 | outputTemplateParameters(OS, Flags); | |||
349 | } | |||
350 | ||||
351 | void LocalStaticGuardIdentifierNode::output(OutputStream &OS, | |||
352 | OutputFlags Flags) const { | |||
353 | if (IsThread) | |||
354 | OS << "`local static thread guard'"; | |||
355 | else | |||
356 | OS << "`local static guard'"; | |||
357 | if (ScopeIndex > 0) | |||
358 | OS << "{" << ScopeIndex << "}"; | |||
359 | } | |||
360 | ||||
361 | void ConversionOperatorIdentifierNode::output(OutputStream &OS, | |||
362 | OutputFlags Flags) const { | |||
363 | OS << "operator"; | |||
364 | outputTemplateParameters(OS, Flags); | |||
365 | OS << " "; | |||
366 | TargetType->output(OS, Flags); | |||
367 | } | |||
368 | ||||
369 | void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { | |||
370 | if (IsDestructor) | |||
371 | OS << "~"; | |||
372 | Class->output(OS, Flags); | |||
373 | outputTemplateParameters(OS, Flags); | |||
374 | } | |||
375 | ||||
376 | void LiteralOperatorIdentifierNode::output(OutputStream &OS, | |||
377 | OutputFlags Flags) const { | |||
378 | OS << "operator \"\"" << Name; | |||
379 | outputTemplateParameters(OS, Flags); | |||
380 | } | |||
381 | ||||
382 | void FunctionSignatureNode::outputPre(OutputStream &OS, | |||
383 | OutputFlags Flags) const { | |||
384 | if (!(Flags & OF_NoAccessSpecifier)) { | |||
385 | if (FunctionClass & FC_Public) | |||
386 | OS << "public: "; | |||
387 | if (FunctionClass & FC_Protected) | |||
388 | OS << "protected: "; | |||
389 | if (FunctionClass & FC_Private) | |||
390 | OS << "private: "; | |||
391 | } | |||
392 | ||||
393 | if (!(Flags & OF_NoMemberType)) { | |||
394 | if (!(FunctionClass & FC_Global)) { | |||
395 | if (FunctionClass & FC_Static) | |||
396 | OS << "static "; | |||
397 | } | |||
398 | if (FunctionClass & FC_Virtual) | |||
399 | OS << "virtual "; | |||
400 | ||||
401 | if (FunctionClass & FC_ExternC) | |||
402 | OS << "extern \"C\" "; | |||
403 | } | |||
404 | ||||
405 | if (!(Flags & OF_NoReturnType) && ReturnType) { | |||
406 | ReturnType->outputPre(OS, Flags); | |||
407 | OS << " "; | |||
408 | } | |||
409 | ||||
410 | if (!(Flags & OF_NoCallingConvention)) | |||
411 | outputCallingConvention(OS, CallConvention); | |||
412 | } | |||
413 | ||||
414 | void FunctionSignatureNode::outputPost(OutputStream &OS, | |||
415 | OutputFlags Flags) const { | |||
416 | if (!(FunctionClass & FC_NoParameterList)) { | |||
417 | OS << "("; | |||
418 | if (Params) | |||
419 | Params->output(OS, Flags); | |||
420 | else | |||
421 | OS << "void"; | |||
422 | ||||
423 | if (IsVariadic) { | |||
424 | if (OS.back() != '(') | |||
425 | OS << ", "; | |||
426 | OS << "..."; | |||
427 | } | |||
428 | OS << ")"; | |||
429 | } | |||
430 | ||||
431 | if (Quals & Q_Const) | |||
432 | OS << " const"; | |||
433 | if (Quals & Q_Volatile) | |||
434 | OS << " volatile"; | |||
435 | if (Quals & Q_Restrict) | |||
436 | OS << " __restrict"; | |||
437 | if (Quals & Q_Unaligned) | |||
438 | OS << " __unaligned"; | |||
439 | ||||
440 | if (IsNoexcept) | |||
441 | OS << " noexcept"; | |||
442 | ||||
443 | if (RefQualifier == FunctionRefQualifier::Reference) | |||
444 | OS << " &"; | |||
445 | else if (RefQualifier == FunctionRefQualifier::RValueReference) | |||
446 | OS << " &&"; | |||
447 | ||||
448 | if (!(Flags & OF_NoReturnType) && ReturnType) | |||
449 | ReturnType->outputPost(OS, Flags); | |||
450 | } | |||
451 | ||||
452 | void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | |||
453 | OS << "[thunk]: "; | |||
454 | ||||
455 | FunctionSignatureNode::outputPre(OS, Flags); | |||
456 | } | |||
457 | ||||
458 | void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const { | |||
459 | if (FunctionClass & FC_StaticThisAdjust) { | |||
460 | OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; | |||
461 | } else if (FunctionClass & FC_VirtualThisAdjust) { | |||
462 | if (FunctionClass & FC_VirtualThisAdjustEx) { | |||
463 | OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " | |||
464 | << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset | |||
465 | << ", " << ThisAdjust.StaticOffset << "}'"; | |||
466 | } else { | |||
467 | OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " | |||
468 | << ThisAdjust.StaticOffset << "}'"; | |||
469 | } | |||
470 | } | |||
471 | ||||
472 | FunctionSignatureNode::outputPost(OS, Flags); | |||
473 | } | |||
474 | ||||
475 | void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | |||
476 | if (Pointee->kind() == NodeKind::FunctionSignature) { | |||
477 | // If this is a pointer to a function, don't output the calling convention. | |||
478 | // It needs to go inside the parentheses. | |||
479 | const FunctionSignatureNode *Sig = | |||
480 | static_cast<const FunctionSignatureNode *>(Pointee); | |||
481 | Sig->outputPre(OS, OF_NoCallingConvention); | |||
482 | } else | |||
483 | Pointee->outputPre(OS, Flags); | |||
484 | ||||
485 | outputSpaceIfNecessary(OS); | |||
486 | ||||
487 | if (Quals & Q_Unaligned) | |||
488 | OS << "__unaligned "; | |||
489 | ||||
490 | if (Pointee->kind() == NodeKind::ArrayType) { | |||
491 | OS << "("; | |||
492 | } else if (Pointee->kind() == NodeKind::FunctionSignature) { | |||
493 | OS << "("; | |||
494 | const FunctionSignatureNode *Sig = | |||
495 | static_cast<const FunctionSignatureNode *>(Pointee); | |||
496 | outputCallingConvention(OS, Sig->CallConvention); | |||
497 | OS << " "; | |||
498 | } | |||
499 | ||||
500 | if (ClassParent) { | |||
501 | ClassParent->output(OS, Flags); | |||
502 | OS << "::"; | |||
503 | } | |||
504 | ||||
505 | switch (Affinity) { | |||
506 | case PointerAffinity::Pointer: | |||
507 | OS << "*"; | |||
508 | break; | |||
509 | case PointerAffinity::Reference: | |||
510 | OS << "&"; | |||
511 | break; | |||
512 | case PointerAffinity::RValueReference: | |||
513 | OS << "&&"; | |||
514 | break; | |||
515 | default: | |||
516 | assert(false)((false) ? static_cast<void> (0) : __assert_fail ("false" , "/build/llvm-toolchain-snapshot-13~++20210413100635+64c24f493e5f/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp" , 516, __PRETTY_FUNCTION__)); | |||
517 | } | |||
518 | outputQualifiers(OS, Quals, false, false); | |||
519 | } | |||
520 | ||||
521 | void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { | |||
522 | if (Pointee->kind() == NodeKind::ArrayType || | |||
523 | Pointee->kind() == NodeKind::FunctionSignature) | |||
524 | OS << ")"; | |||
525 | ||||
526 | Pointee->outputPost(OS, Flags); | |||
527 | } | |||
528 | ||||
529 | void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | |||
530 | if (!(Flags & OF_NoTagSpecifier)) { | |||
531 | switch (Tag) { | |||
532 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class")case TagKind::Class: OS << "class"; break;; | |||
533 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct")case TagKind::Struct: OS << "struct"; break;; | |||
534 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union")case TagKind::Union: OS << "union"; break;; | |||
535 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum")case TagKind::Enum: OS << "enum"; break;; | |||
536 | } | |||
537 | OS << " "; | |||
538 | } | |||
539 | QualifiedName->output(OS, Flags); | |||
540 | outputQualifiers(OS, Quals, true, false); | |||
541 | } | |||
542 | ||||
543 | void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} | |||
544 | ||||
545 | void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | |||
546 | ElementType->outputPre(OS, Flags); | |||
547 | outputQualifiers(OS, Quals, true, false); | |||
548 | } | |||
549 | ||||
550 | void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags, | |||
551 | Node *N) const { | |||
552 | assert(N->kind() == NodeKind::IntegerLiteral)((N->kind() == NodeKind::IntegerLiteral) ? static_cast< void> (0) : __assert_fail ("N->kind() == NodeKind::IntegerLiteral" , "/build/llvm-toolchain-snapshot-13~++20210413100635+64c24f493e5f/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp" , 552, __PRETTY_FUNCTION__)); | |||
553 | IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N); | |||
554 | if (ILN->Value != 0) | |||
555 | ILN->output(OS, Flags); | |||
556 | } | |||
557 | ||||
558 | void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS, | |||
559 | OutputFlags Flags) const { | |||
560 | if (Dimensions->Count == 0) | |||
561 | return; | |||
562 | ||||
563 | outputOneDimension(OS, Flags, Dimensions->Nodes[0]); | |||
564 | for (size_t I = 1; I < Dimensions->Count; ++I) { | |||
565 | OS << "]["; | |||
566 | outputOneDimension(OS, Flags, Dimensions->Nodes[I]); | |||
567 | } | |||
568 | } | |||
569 | ||||
570 | void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { | |||
571 | OS << "["; | |||
572 | outputDimensionsImpl(OS, Flags); | |||
573 | OS << "]"; | |||
574 | ||||
575 | ElementType->outputPost(OS, Flags); | |||
576 | } | |||
577 | ||||
578 | void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const { | |||
579 | Name->output(OS, Flags); | |||
580 | } | |||
581 | ||||
582 | void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { | |||
583 | Signature->outputPre(OS, Flags); | |||
584 | outputSpaceIfNecessary(OS); | |||
585 | Name->output(OS, Flags); | |||
586 | Signature->outputPost(OS, Flags); | |||
587 | } | |||
588 | ||||
589 | void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { | |||
590 | const char *AccessSpec = nullptr; | |||
591 | bool IsStatic = true; | |||
592 | switch (SC) { | |||
593 | case StorageClass::PrivateStatic: | |||
594 | AccessSpec = "private"; | |||
595 | break; | |||
596 | case StorageClass::PublicStatic: | |||
597 | AccessSpec = "public"; | |||
598 | break; | |||
599 | case StorageClass::ProtectedStatic: | |||
600 | AccessSpec = "protected"; | |||
601 | break; | |||
602 | default: | |||
603 | IsStatic = false; | |||
604 | break; | |||
605 | } | |||
606 | if (!(Flags & OF_NoAccessSpecifier) && AccessSpec) | |||
607 | OS << AccessSpec << ": "; | |||
608 | if (!(Flags & OF_NoMemberType) && IsStatic) | |||
609 | OS << "static "; | |||
610 | ||||
611 | if (Type) { | |||
612 | Type->outputPre(OS, Flags); | |||
613 | outputSpaceIfNecessary(OS); | |||
614 | } | |||
615 | Name->output(OS, Flags); | |||
616 | if (Type) | |||
617 | Type->outputPost(OS, Flags); | |||
618 | } | |||
619 | ||||
620 | void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | |||
621 | Identifier->output(OS, Flags); | |||
622 | } | |||
623 | void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} | |||
624 | ||||
625 | void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const { | |||
626 | Components->output(OS, Flags, "::"); | |||
627 | } | |||
628 | ||||
629 | void RttiBaseClassDescriptorNode::output(OutputStream &OS, | |||
630 | OutputFlags Flags) const { | |||
631 | OS << "`RTTI Base Class Descriptor at ("; | |||
632 | OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " | |||
633 | << this->Flags; | |||
634 | OS << ")'"; | |||
635 | } | |||
636 | ||||
637 | void LocalStaticGuardVariableNode::output(OutputStream &OS, | |||
638 | OutputFlags Flags) const { | |||
639 | Name->output(OS, Flags); | |||
640 | } | |||
641 | ||||
642 | void VcallThunkIdentifierNode::output(OutputStream &OS, | |||
643 | OutputFlags Flags) const { | |||
644 | OS << "`vcall'{" << OffsetInVTable << ", {flat}}"; | |||
645 | } | |||
646 | ||||
647 | void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { | |||
648 | outputQualifiers(OS, Quals, false, true); | |||
649 | Name->output(OS, Flags); | |||
650 | if (TargetName) { | |||
651 | OS << "{for `"; | |||
652 | TargetName->output(OS, Flags); | |||
653 | OS << "'}"; | |||
654 | } | |||
655 | } |
1 | //===--- Utility.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 | // Provide some utility classes for use in the demangler(s). |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_DEMANGLE_UTILITY_H |
14 | #define LLVM_DEMANGLE_UTILITY_H |
15 | |
16 | #include "StringView.h" |
17 | #include <cstdint> |
18 | #include <cstdlib> |
19 | #include <cstring> |
20 | #include <iterator> |
21 | #include <limits> |
22 | |
23 | DEMANGLE_NAMESPACE_BEGINnamespace llvm { namespace itanium_demangle { |
24 | |
25 | // Stream that AST nodes write their string representation into after the AST |
26 | // has been parsed. |
27 | class OutputStream { |
28 | char *Buffer = nullptr; |
29 | size_t CurrentPosition = 0; |
30 | size_t BufferCapacity = 0; |
31 | |
32 | // Ensure there is at least n more positions in buffer. |
33 | void grow(size_t N) { |
34 | if (N + CurrentPosition >= BufferCapacity) { |
35 | BufferCapacity *= 2; |
36 | if (BufferCapacity < N + CurrentPosition) |
37 | BufferCapacity = N + CurrentPosition; |
38 | Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); |
39 | if (Buffer == nullptr) |
40 | std::terminate(); |
41 | } |
42 | } |
43 | |
44 | void writeUnsigned(uint64_t N, bool isNeg = false) { |
45 | // Handle special case... |
46 | if (N == 0) { |
47 | *this << '0'; |
48 | return; |
49 | } |
50 | |
51 | char Temp[21]; |
52 | char *TempPtr = std::end(Temp); |
53 | |
54 | while (N) { |
55 | *--TempPtr = char('0' + N % 10); |
56 | N /= 10; |
57 | } |
58 | |
59 | // Add negative sign... |
60 | if (isNeg) |
61 | *--TempPtr = '-'; |
62 | this->operator<<(StringView(TempPtr, std::end(Temp))); |
63 | } |
64 | |
65 | public: |
66 | OutputStream(char *StartBuf, size_t Size) |
67 | : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} |
68 | OutputStream() = default; |
69 | void reset(char *Buffer_, size_t BufferCapacity_) { |
70 | CurrentPosition = 0; |
71 | Buffer = Buffer_; |
72 | BufferCapacity = BufferCapacity_; |
73 | } |
74 | |
75 | /// If a ParameterPackExpansion (or similar type) is encountered, the offset |
76 | /// into the pack that we're currently printing. |
77 | unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); |
78 | unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); |
79 | |
80 | OutputStream &operator+=(StringView R) { |
81 | size_t Size = R.size(); |
82 | if (Size == 0) |
83 | return *this; |
84 | grow(Size); |
85 | std::memmove(Buffer + CurrentPosition, R.begin(), Size); |
86 | CurrentPosition += Size; |
87 | return *this; |
88 | } |
89 | |
90 | OutputStream &operator+=(char C) { |
91 | grow(1); |
92 | Buffer[CurrentPosition++] = C; |
93 | return *this; |
94 | } |
95 | |
96 | OutputStream &operator<<(StringView R) { return (*this += R); } |
97 | |
98 | OutputStream &operator<<(char C) { return (*this += C); } |
99 | |
100 | OutputStream &operator<<(long long N) { |
101 | if (N < 0) |
102 | writeUnsigned(static_cast<unsigned long long>(-N), true); |
103 | else |
104 | writeUnsigned(static_cast<unsigned long long>(N)); |
105 | return *this; |
106 | } |
107 | |
108 | OutputStream &operator<<(unsigned long long N) { |
109 | writeUnsigned(N, false); |
110 | return *this; |
111 | } |
112 | |
113 | OutputStream &operator<<(long N) { |
114 | return this->operator<<(static_cast<long long>(N)); |
115 | } |
116 | |
117 | OutputStream &operator<<(unsigned long N) { |
118 | return this->operator<<(static_cast<unsigned long long>(N)); |
119 | } |
120 | |
121 | OutputStream &operator<<(int N) { |
122 | return this->operator<<(static_cast<long long>(N)); |
123 | } |
124 | |
125 | OutputStream &operator<<(unsigned int N) { |
126 | return this->operator<<(static_cast<unsigned long long>(N)); |
127 | } |
128 | |
129 | size_t getCurrentPosition() const { return CurrentPosition; } |
130 | void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } |
131 | |
132 | char back() const { |
133 | return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; |
134 | } |
135 | |
136 | bool empty() const { return CurrentPosition == 0; } |
137 | |
138 | char *getBuffer() { return Buffer; } |
139 | char *getBufferEnd() { return Buffer + CurrentPosition - 1; } |
140 | size_t getBufferCapacity() const { return BufferCapacity; } |
141 | }; |
142 | |
143 | template <class T> class SwapAndRestore { |
144 | T &Restore; |
145 | T OriginalValue; |
146 | bool ShouldRestore = true; |
147 | |
148 | public: |
149 | SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} |
150 | |
151 | SwapAndRestore(T &Restore_, T NewVal) |
152 | : Restore(Restore_), OriginalValue(Restore) { |
153 | Restore = std::move(NewVal); |
154 | } |
155 | ~SwapAndRestore() { |
156 | if (ShouldRestore) |
157 | Restore = std::move(OriginalValue); |
158 | } |
159 | |
160 | void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } |
161 | |
162 | void restoreNow(bool Force) { |
163 | if (!Force && !ShouldRestore) |
164 | return; |
165 | |
166 | Restore = std::move(OriginalValue); |
167 | ShouldRestore = false; |
168 | } |
169 | |
170 | SwapAndRestore(const SwapAndRestore &) = delete; |
171 | SwapAndRestore &operator=(const SwapAndRestore &) = delete; |
172 | }; |
173 | |
174 | inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, |
175 | size_t InitSize) { |
176 | size_t BufferSize; |
177 | if (Buf == nullptr) { |
178 | Buf = static_cast<char *>(std::malloc(InitSize)); |
179 | if (Buf == nullptr) |
180 | return false; |
181 | BufferSize = InitSize; |
182 | } else |
183 | BufferSize = *N; |
184 | |
185 | S.reset(Buf, BufferSize); |
186 | return true; |
187 | } |
188 | |
189 | DEMANGLE_NAMESPACE_END} } |
190 | |
191 | #endif |