1343171Sdim//===- NativeTypeEnum.cpp - info about enum type ----------------*- C++ -*-===//
2343171Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6343171Sdim//
7343171Sdim//===----------------------------------------------------------------------===//
8343171Sdim
9343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
10343171Sdim
11343171Sdim#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
12343171Sdim#include "llvm/DebugInfo/CodeView/TypeRecord.h"
13343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
14343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h"
15343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
16343171Sdim#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
17343171Sdim#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
18343171Sdim#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
19343171Sdim#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
20343171Sdim
21343171Sdim#include "llvm/Support/FormatVariadic.h"
22343171Sdim
23343171Sdim#include <cassert>
24343171Sdim
25343171Sdimusing namespace llvm;
26343171Sdimusing namespace llvm::codeview;
27343171Sdimusing namespace llvm::pdb;
28343171Sdim
29343171Sdimnamespace {
30343171Sdim// Yea, this is a pretty terrible class name.  But if we have an enum:
31343171Sdim//
32343171Sdim// enum Foo {
33343171Sdim//  A,
34343171Sdim//  B
35343171Sdim// };
36343171Sdim//
37343171Sdim// then A and B are the "enumerators" of the "enum" Foo.  And we need
38343171Sdim// to enumerate them.
39343171Sdimclass NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks {
40343171Sdimpublic:
41343171Sdim  NativeEnumEnumEnumerators(NativeSession &Session,
42343171Sdim                            const NativeTypeEnum &ClassParent);
43343171Sdim
44343171Sdim  uint32_t getChildCount() const override;
45343171Sdim  std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override;
46343171Sdim  std::unique_ptr<PDBSymbol> getNext() override;
47343171Sdim  void reset() override;
48343171Sdim
49343171Sdimprivate:
50343171Sdim  Error visitKnownMember(CVMemberRecord &CVM,
51343171Sdim                         EnumeratorRecord &Record) override;
52343171Sdim  Error visitKnownMember(CVMemberRecord &CVM,
53343171Sdim                         ListContinuationRecord &Record) override;
54343171Sdim
55343171Sdim  NativeSession &Session;
56343171Sdim  const NativeTypeEnum &ClassParent;
57343171Sdim  std::vector<EnumeratorRecord> Enumerators;
58343171Sdim  Optional<TypeIndex> ContinuationIndex;
59343171Sdim  uint32_t Index = 0;
60343171Sdim};
61343171Sdim} // namespace
62343171Sdim
63343171SdimNativeEnumEnumEnumerators::NativeEnumEnumEnumerators(
64343171Sdim    NativeSession &Session, const NativeTypeEnum &ClassParent)
65343171Sdim    : Session(Session), ClassParent(ClassParent) {
66343171Sdim  TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream());
67343171Sdim  LazyRandomTypeCollection &Types = Tpi.typeCollection();
68343171Sdim
69343171Sdim  ContinuationIndex = ClassParent.getEnumRecord().FieldList;
70343171Sdim  while (ContinuationIndex) {
71343171Sdim    CVType FieldList = Types.getType(*ContinuationIndex);
72343171Sdim    assert(FieldList.kind() == LF_FIELDLIST);
73343171Sdim    ContinuationIndex.reset();
74343171Sdim    cantFail(visitMemberRecordStream(FieldList.data(), *this));
75343171Sdim  }
76343171Sdim}
77343171Sdim
78343171SdimError NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM,
79343171Sdim                                                  EnumeratorRecord &Record) {
80343171Sdim  Enumerators.push_back(Record);
81343171Sdim  return Error::success();
82343171Sdim}
83343171Sdim
84343171SdimError NativeEnumEnumEnumerators::visitKnownMember(
85343171Sdim    CVMemberRecord &CVM, ListContinuationRecord &Record) {
86343171Sdim  ContinuationIndex = Record.ContinuationIndex;
87343171Sdim  return Error::success();
88343171Sdim}
89343171Sdim
90343171Sdimuint32_t NativeEnumEnumEnumerators::getChildCount() const {
91343171Sdim  return Enumerators.size();
92343171Sdim}
93343171Sdim
94343171Sdimstd::unique_ptr<PDBSymbol>
95343171SdimNativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const {
96343171Sdim  if (Index >= getChildCount())
97343171Sdim    return nullptr;
98343171Sdim
99343171Sdim  SymIndexId Id = Session.getSymbolCache()
100343171Sdim                      .getOrCreateFieldListMember<NativeSymbolEnumerator>(
101343171Sdim                          ClassParent.getEnumRecord().FieldList, Index,
102343171Sdim                          ClassParent, Enumerators[Index]);
103343171Sdim  return Session.getSymbolCache().getSymbolById(Id);
104343171Sdim}
105343171Sdim
106343171Sdimstd::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() {
107343171Sdim  if (Index >= getChildCount())
108343171Sdim    return nullptr;
109343171Sdim
110343171Sdim  return getChildAtIndex(Index++);
111343171Sdim}
112343171Sdim
113343171Sdimvoid NativeEnumEnumEnumerators::reset() { Index = 0; }
114343171Sdim
115343171SdimNativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
116343171Sdim                               TypeIndex Index, EnumRecord Record)
117343171Sdim    : NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index),
118343171Sdim      Record(std::move(Record)) {}
119343171Sdim
120343171SdimNativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
121343171Sdim                               NativeTypeEnum &UnmodifiedType,
122343171Sdim                               codeview::ModifierRecord Modifier)
123343171Sdim    : NativeRawSymbol(Session, PDB_SymType::Enum, Id),
124343171Sdim      UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {}
125343171Sdim
126343171SdimNativeTypeEnum::~NativeTypeEnum() {}
127343171Sdim
128343171Sdimvoid NativeTypeEnum::dump(raw_ostream &OS, int Indent,
129343171Sdim                          PdbSymbolIdField ShowIdFields,
130343171Sdim                          PdbSymbolIdField RecurseIdFields) const {
131343171Sdim  NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
132343171Sdim
133343171Sdim  dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()),
134343171Sdim                  Indent);
135343171Sdim  dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
136343171Sdim                    PdbSymbolIdField::LexicalParent, ShowIdFields,
137343171Sdim                    RecurseIdFields);
138343171Sdim  dumpSymbolField(OS, "name", getName(), Indent);
139343171Sdim  dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
140343171Sdim                    PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
141343171Sdim  if (Modifiers.hasValue())
142343171Sdim    dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent,
143343171Sdim                      Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields,
144343171Sdim                      RecurseIdFields);
145343171Sdim  dumpSymbolField(OS, "length", getLength(), Indent);
146343171Sdim  dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
147343171Sdim  dumpSymbolField(OS, "constType", isConstType(), Indent);
148343171Sdim  dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent);
149343171Sdim  dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent);
150343171Sdim  dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent);
151343171Sdim  dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent);
152343171Sdim  dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent);
153343171Sdim  dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent);
154343171Sdim  dumpSymbolField(OS, "nested", isNested(), Indent);
155343171Sdim  dumpSymbolField(OS, "packed", isPacked(), Indent);
156343171Sdim  dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent);
157343171Sdim  dumpSymbolField(OS, "scoped", isScoped(), Indent);
158343171Sdim  dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
159343171Sdim  dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent);
160343171Sdim  dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
161343171Sdim}
162343171Sdim
163343171Sdimstd::unique_ptr<IPDBEnumSymbols>
164343171SdimNativeTypeEnum::findChildren(PDB_SymType Type) const {
165343171Sdim  if (Type != PDB_SymType::Data)
166360784Sdim    return std::make_unique<NullEnumerator<PDBSymbol>>();
167343171Sdim
168343171Sdim  const NativeTypeEnum *ClassParent = nullptr;
169343171Sdim  if (!Modifiers)
170343171Sdim    ClassParent = this;
171343171Sdim  else
172343171Sdim    ClassParent = UnmodifiedType;
173360784Sdim  return std::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent);
174343171Sdim}
175343171Sdim
176343171SdimPDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; }
177343171Sdim
178343171SdimPDB_BuiltinType NativeTypeEnum::getBuiltinType() const {
179343171Sdim  if (UnmodifiedType)
180343171Sdim    return UnmodifiedType->getBuiltinType();
181343171Sdim
182343171Sdim  Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType());
183343171Sdim
184343171Sdim  codeview::TypeIndex Underlying = Record->getUnderlyingType();
185343171Sdim
186343171Sdim  // This indicates a corrupt record.
187343171Sdim  if (!Underlying.isSimple() ||
188343171Sdim      Underlying.getSimpleMode() != SimpleTypeMode::Direct) {
189343171Sdim    return PDB_BuiltinType::None;
190343171Sdim  }
191343171Sdim
192343171Sdim  switch (Underlying.getSimpleKind()) {
193343171Sdim  case SimpleTypeKind::Boolean128:
194343171Sdim  case SimpleTypeKind::Boolean64:
195343171Sdim  case SimpleTypeKind::Boolean32:
196343171Sdim  case SimpleTypeKind::Boolean16:
197343171Sdim  case SimpleTypeKind::Boolean8:
198343171Sdim    return PDB_BuiltinType::Bool;
199343171Sdim  case SimpleTypeKind::NarrowCharacter:
200343171Sdim  case SimpleTypeKind::UnsignedCharacter:
201343171Sdim  case SimpleTypeKind::SignedCharacter:
202343171Sdim    return PDB_BuiltinType::Char;
203343171Sdim  case SimpleTypeKind::WideCharacter:
204343171Sdim    return PDB_BuiltinType::WCharT;
205343171Sdim  case SimpleTypeKind::Character16:
206343171Sdim    return PDB_BuiltinType::Char16;
207343171Sdim  case SimpleTypeKind::Character32:
208343171Sdim    return PDB_BuiltinType::Char32;
209343171Sdim  case SimpleTypeKind::Int128:
210343171Sdim  case SimpleTypeKind::Int128Oct:
211343171Sdim  case SimpleTypeKind::Int16:
212343171Sdim  case SimpleTypeKind::Int16Short:
213343171Sdim  case SimpleTypeKind::Int32:
214343171Sdim  case SimpleTypeKind::Int32Long:
215343171Sdim  case SimpleTypeKind::Int64:
216343171Sdim  case SimpleTypeKind::Int64Quad:
217343171Sdim    return PDB_BuiltinType::Int;
218343171Sdim  case SimpleTypeKind::UInt128:
219343171Sdim  case SimpleTypeKind::UInt128Oct:
220343171Sdim  case SimpleTypeKind::UInt16:
221343171Sdim  case SimpleTypeKind::UInt16Short:
222343171Sdim  case SimpleTypeKind::UInt32:
223343171Sdim  case SimpleTypeKind::UInt32Long:
224343171Sdim  case SimpleTypeKind::UInt64:
225343171Sdim  case SimpleTypeKind::UInt64Quad:
226343171Sdim    return PDB_BuiltinType::UInt;
227343171Sdim  case SimpleTypeKind::HResult:
228343171Sdim    return PDB_BuiltinType::HResult;
229343171Sdim  case SimpleTypeKind::Complex16:
230343171Sdim  case SimpleTypeKind::Complex32:
231343171Sdim  case SimpleTypeKind::Complex32PartialPrecision:
232343171Sdim  case SimpleTypeKind::Complex64:
233343171Sdim  case SimpleTypeKind::Complex80:
234343171Sdim  case SimpleTypeKind::Complex128:
235343171Sdim    return PDB_BuiltinType::Complex;
236343171Sdim  case SimpleTypeKind::Float16:
237343171Sdim  case SimpleTypeKind::Float32:
238343171Sdim  case SimpleTypeKind::Float32PartialPrecision:
239343171Sdim  case SimpleTypeKind::Float48:
240343171Sdim  case SimpleTypeKind::Float64:
241343171Sdim  case SimpleTypeKind::Float80:
242343171Sdim  case SimpleTypeKind::Float128:
243343171Sdim    return PDB_BuiltinType::Float;
244343171Sdim  default:
245343171Sdim    return PDB_BuiltinType::None;
246343171Sdim  }
247343171Sdim  llvm_unreachable("Unreachable");
248343171Sdim}
249343171Sdim
250343171SdimSymIndexId NativeTypeEnum::getUnmodifiedTypeId() const {
251343171Sdim  return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0;
252343171Sdim}
253343171Sdim
254343171Sdimbool NativeTypeEnum::hasConstructor() const {
255343171Sdim  if (UnmodifiedType)
256343171Sdim    return UnmodifiedType->hasConstructor();
257343171Sdim
258343171Sdim  return bool(Record->getOptions() &
259343171Sdim              codeview::ClassOptions::HasConstructorOrDestructor);
260343171Sdim}
261343171Sdim
262343171Sdimbool NativeTypeEnum::hasAssignmentOperator() const {
263343171Sdim  if (UnmodifiedType)
264343171Sdim    return UnmodifiedType->hasAssignmentOperator();
265343171Sdim
266343171Sdim  return bool(Record->getOptions() &
267343171Sdim              codeview::ClassOptions::HasOverloadedAssignmentOperator);
268343171Sdim}
269343171Sdim
270343171Sdimbool NativeTypeEnum::hasNestedTypes() const {
271343171Sdim  if (UnmodifiedType)
272343171Sdim    return UnmodifiedType->hasNestedTypes();
273343171Sdim
274343171Sdim  return bool(Record->getOptions() &
275343171Sdim              codeview::ClassOptions::ContainsNestedClass);
276343171Sdim}
277343171Sdim
278343171Sdimbool NativeTypeEnum::isIntrinsic() const {
279343171Sdim  if (UnmodifiedType)
280343171Sdim    return UnmodifiedType->isIntrinsic();
281343171Sdim
282343171Sdim  return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic);
283343171Sdim}
284343171Sdim
285343171Sdimbool NativeTypeEnum::hasCastOperator() const {
286343171Sdim  if (UnmodifiedType)
287343171Sdim    return UnmodifiedType->hasCastOperator();
288343171Sdim
289343171Sdim  return bool(Record->getOptions() &
290343171Sdim              codeview::ClassOptions::HasConversionOperator);
291343171Sdim}
292343171Sdim
293343171Sdimuint64_t NativeTypeEnum::getLength() const {
294343171Sdim  if (UnmodifiedType)
295343171Sdim    return UnmodifiedType->getLength();
296343171Sdim
297343171Sdim  const auto Id = Session.getSymbolCache().findSymbolByTypeIndex(
298343171Sdim      Record->getUnderlyingType());
299343171Sdim  const auto UnderlyingType =
300343171Sdim      Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id);
301343171Sdim  return UnderlyingType ? UnderlyingType->getLength() : 0;
302343171Sdim}
303343171Sdim
304343171Sdimstd::string NativeTypeEnum::getName() const {
305343171Sdim  if (UnmodifiedType)
306343171Sdim    return UnmodifiedType->getName();
307343171Sdim
308343171Sdim  return Record->getName();
309343171Sdim}
310343171Sdim
311343171Sdimbool NativeTypeEnum::isNested() const {
312343171Sdim  if (UnmodifiedType)
313343171Sdim    return UnmodifiedType->isNested();
314343171Sdim
315343171Sdim  return bool(Record->getOptions() & codeview::ClassOptions::Nested);
316343171Sdim}
317343171Sdim
318343171Sdimbool NativeTypeEnum::hasOverloadedOperator() const {
319343171Sdim  if (UnmodifiedType)
320343171Sdim    return UnmodifiedType->hasOverloadedOperator();
321343171Sdim
322343171Sdim  return bool(Record->getOptions() &
323343171Sdim              codeview::ClassOptions::HasOverloadedOperator);
324343171Sdim}
325343171Sdim
326343171Sdimbool NativeTypeEnum::isPacked() const {
327343171Sdim  if (UnmodifiedType)
328343171Sdim    return UnmodifiedType->isPacked();
329343171Sdim
330343171Sdim  return bool(Record->getOptions() & codeview::ClassOptions::Packed);
331343171Sdim}
332343171Sdim
333343171Sdimbool NativeTypeEnum::isScoped() const {
334343171Sdim  if (UnmodifiedType)
335343171Sdim    return UnmodifiedType->isScoped();
336343171Sdim
337343171Sdim  return bool(Record->getOptions() & codeview::ClassOptions::Scoped);
338343171Sdim}
339343171Sdim
340343171SdimSymIndexId NativeTypeEnum::getTypeId() const {
341343171Sdim  if (UnmodifiedType)
342343171Sdim    return UnmodifiedType->getTypeId();
343343171Sdim
344343171Sdim  return Session.getSymbolCache().findSymbolByTypeIndex(
345343171Sdim      Record->getUnderlyingType());
346343171Sdim}
347343171Sdim
348343171Sdimbool NativeTypeEnum::isRefUdt() const { return false; }
349343171Sdim
350343171Sdimbool NativeTypeEnum::isValueUdt() const { return false; }
351343171Sdim
352343171Sdimbool NativeTypeEnum::isInterfaceUdt() const { return false; }
353343171Sdim
354343171Sdimbool NativeTypeEnum::isConstType() const {
355343171Sdim  if (!Modifiers)
356343171Sdim    return false;
357343171Sdim  return ((Modifiers->getModifiers() & ModifierOptions::Const) !=
358343171Sdim          ModifierOptions::None);
359343171Sdim}
360343171Sdim
361343171Sdimbool NativeTypeEnum::isVolatileType() const {
362343171Sdim  if (!Modifiers)
363343171Sdim    return false;
364343171Sdim  return ((Modifiers->getModifiers() & ModifierOptions::Volatile) !=
365343171Sdim          ModifierOptions::None);
366343171Sdim}
367343171Sdim
368343171Sdimbool NativeTypeEnum::isUnalignedType() const {
369343171Sdim  if (!Modifiers)
370343171Sdim    return false;
371343171Sdim  return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) !=
372343171Sdim          ModifierOptions::None);
373343171Sdim}
374343171Sdim
375343171Sdimconst NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const {
376343171Sdim  if (UnmodifiedType)
377343171Sdim    return UnmodifiedType->getUnderlyingBuiltinType();
378343171Sdim
379343171Sdim  return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>(
380343171Sdim      getTypeId());
381343171Sdim}
382