aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/include/lldb/Symbol/Type.h
blob: 307be6c55e01613975e9163f958e685c522cc6e1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
//===-- Type.h --------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_SYMBOL_TYPE_H
#define LLDB_SYMBOL_TYPE_H

#include "lldb/Core/Declaration.h"
#include "lldb/Symbol/CompilerDecl.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Symbol/TypeMap.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"

#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/DenseSet.h"

#include <optional>
#include <set>

namespace lldb_private {
class SymbolFileCommon;

/// A SmallBitVector that represents a set of source languages (\p
/// lldb::LanguageType).  Each lldb::LanguageType is represented by
/// the bit with the position of its enumerator. The largest
/// LanguageType is < 64, so this is space-efficient and on 64-bit
/// architectures a LanguageSet can be completely stack-allocated.
struct LanguageSet {
  llvm::SmallBitVector bitvector;
  LanguageSet();

  /// If the set contains a single language only, return it.
  std::optional<lldb::LanguageType> GetSingularLanguage();
  void Insert(lldb::LanguageType language);
  bool Empty() const;
  size_t Size() const;
  bool operator[](unsigned i) const;
};

/// CompilerContext allows an array of these items to be passed to perform
/// detailed lookups in SymbolVendor and SymbolFile functions.
struct CompilerContext {
  CompilerContext(CompilerContextKind t, ConstString n) : kind(t), name(n) {}

  bool operator==(const CompilerContext &rhs) const {
    return kind == rhs.kind && name == rhs.name;
  }
  bool operator!=(const CompilerContext &rhs) const { return !(*this == rhs); }

  void Dump(Stream &s) const;

  CompilerContextKind kind;
  ConstString name;
};

/// Match \p context_chain against \p pattern, which may contain "Any"
/// kinds. The \p context_chain should *not* contain any "Any" kinds.
bool contextMatches(llvm::ArrayRef<CompilerContext> context_chain,
                    llvm::ArrayRef<CompilerContext> pattern);

FLAGS_ENUM(TypeQueryOptions){
    e_none = 0u,
    /// If set, TypeQuery::m_context contains an exact context that must match
    /// the full context. If not set, TypeQuery::m_context can contain a partial
    /// type match where the full context isn't fully specified.
    e_exact_match = (1u << 0),
    /// If set, TypeQuery::m_context is a clang module compiler context. If not
    /// set TypeQuery::m_context is normal type lookup context.
    e_module_search = (1u << 1),
    /// When true, the find types call should stop the query as soon as a single
    /// matching type is found. When false, the type query should find all
    /// matching types.
    e_find_one = (1u << 2),
};
LLDB_MARK_AS_BITMASK_ENUM(TypeQueryOptions)

/// A class that contains all state required for type lookups.
///
/// Using a TypeQuery class for matching types simplifies the internal APIs we
/// need to implement type lookups in LLDB. Type lookups can fully specify the
/// exact typename by filling out a complete or partial CompilerContext array.
/// This technique allows for powerful searches and also allows the SymbolFile
/// classes to use the m_context array to lookup types by basename, then
/// eliminate potential matches without having to resolve types into each
/// TypeSystem. This makes type lookups vastly more efficient and allows the
/// SymbolFile objects to stop looking up types when the type matching is
/// complete, like if we are looking for only a single type in our search.
class TypeQuery {
public:
  TypeQuery() = delete;

  /// Construct a type match object using a fully- or partially-qualified name.
  ///
  /// The specified \a type_name will be chopped up and the m_context will be
  /// populated by separating the string by looking for "::". We do this because
  /// symbol files have indexes that contain only the type's basename. This also
  /// allows symbol files to efficiently not realize types that don't match the
  /// specified context. Example of \a type_name values that can be specified
  /// include:
  ///   "foo": Look for any type whose basename matches "foo".
  ///     If \a exact_match is true, then the type can't be contained in any
  ///     declaration context like a namespace, class, or other containing
  ///     scope.
  ///     If \a exact match is false, then we will find all matches including
  ///     ones that are contained in other declaration contexts, including top
  ///     level types.
  ///   "foo::bar": Look for any type whose basename matches "bar" but make sure
  ///     its parent declaration context is any named declaration context
  ///     (namespace, class, struct, etc) whose name matches "foo".
  ///     If \a exact_match is true, then the "foo" declaration context must
  ///     appear at the source file level or inside of a function.
  ///     If \a exact match is false, then the "foo" declaration context can
  ///     be contained in any other declaration contexts.
  ///   "class foo": Only match types that are classes whose basename matches
  ///     "foo".
  ///   "struct foo": Only match types that are structures whose basename
  ///     matches "foo".
  ///   "class foo::bar": Only match types that are classes whose basename
  ///     matches "bar" and that are contained in any named declaration context
  ///     named "foo".
  ///
  /// \param[in] type_name
  ///   A fully- or partially-qualified type name. This name will be parsed and
  ///   broken up and the m_context will be populated with the various parts of
  ///   the name. This typename can be prefixed with "struct ", "class ",
  ///   "union", "enum " or "typedef " before the actual type name to limit the
  ///   results of the types that match. The declaration context can be
  ///   specified with the "::" string. For example, "a::b::my_type".
  ///
  /// \param[in] options A set of boolean enumeration flags from the
  ///   TypeQueryOptions enumerations. \see TypeQueryOptions.
  TypeQuery(llvm::StringRef name, TypeQueryOptions options = e_none);

  /// Construct a type-match object that matches a type basename that exists
  /// in the specified declaration context.
  ///
  /// This allows the m_context to be first populated using a declaration
  /// context to exactly identify the containing declaration context of a type.
  /// This can be used when you have a forward declaration to a type and you
  /// need to search for its complete type.
  ///
  /// \param[in] decl_ctx
  ///   A declaration context object that comes from a TypeSystem plug-in. This
  ///   object will be asked to populate the array of CompilerContext objects
  ///   by adding the top most declaration context first into the array and then
  ///   adding any containing declaration contexts.
  ///
  /// \param[in] type_basename
  ///   The basename of the type to lookup in the specified declaration context.
  ///
  /// \param[in] options A set of boolean enumeration flags from the
  ///   TypeQueryOptions enumerations. \see TypeQueryOptions.
  TypeQuery(const CompilerDeclContext &decl_ctx, ConstString type_basename,
            TypeQueryOptions options = e_none);
  /// Construct a type-match object using a compiler declaration that specifies
  /// a typename and a declaration context to use when doing exact type lookups.
  ///
  /// This allows the m_context to be first populated using a type declaration.
  /// The type declaration might have a declaration context and each TypeSystem
  /// plug-in can populate the declaration context needed to perform an exact
  /// lookup for a type.
  /// This can be used when you have a forward declaration to a type and you
  /// need to search for its complete type.
  ///
  /// \param[in] decl
  ///   A type declaration context object that comes from a TypeSystem plug-in.
  ///   This object will be asked to full the array of CompilerContext objects
  ///   by adding the top most declaration context first into the array and then
  ///   adding any containing declaration contexts, and ending with the exact
  ///   typename and the kind of type it is (class, struct, union, enum, etc).
  ///
  /// \param[in] options A set of boolean enumeration flags from the
  ///   TypeQueryOptions enumerations. \see TypeQueryOptions.
  TypeQuery(const CompilerDecl &decl, TypeQueryOptions options = e_none);

  /// Construct a type-match object using a CompilerContext array.
  ///
  /// Clients can manually create compiler contexts and use these to find
  /// matches when searching for types. There are two types of contexts that
  /// are supported when doing type searchs: type contexts and clang module
  /// contexts. Type contexts have contexts that specify the type and its
  /// containing declaration context like namespaces and classes. Clang module
  /// contexts specify contexts more completely to find exact matches within
  /// clang module debug information. They will include the modules that the
  /// type is included in and any functions that the type might be defined in.
  /// This allows very fine-grained type resolution.
  ///
  /// \param[in] context The compiler context to use when doing the search.
  ///
  /// \param[in] options A set of boolean enumeration flags from the
  ///   TypeQueryOptions enumerations. \see TypeQueryOptions.
  TypeQuery(const llvm::ArrayRef<lldb_private::CompilerContext> &context,
            TypeQueryOptions options = e_none);

  /// Construct a type-match object that duplicates all matching criterea,
  /// but not any searched symbol files or the type map for matches. This allows
  /// the m_context to be modified prior to performing another search.
  TypeQuery(const TypeQuery &rhs) = default;
  /// Assign a type-match object that duplicates all matching criterea,
  /// but not any searched symbol files or the type map for matches. This allows
  /// the m_context to be modified prior to performing another search.
  TypeQuery &operator=(const TypeQuery &rhs) = default;

  /// Check of a CompilerContext array from matching type from a symbol file
  /// matches the \a m_context.
  ///
  /// \param[in] context
  ///   A fully qualified CompilerContext array for a potential match that is
  ///   created by the symbol file prior to trying to actually resolve a type.
  ///
  /// \returns
  ///   True if the context matches, false if it doesn't. If e_exact_match
  ///   is set in m_options, then \a context must exactly match \a m_context. If
  ///   e_exact_match is not set, then the bottom m_context.size() objects in
  ///   \a context must match. This allows SymbolFile objects the fill in a
  ///   potential type basename match from the index into \a context, and see if
  ///   it matches prior to having to resolve a lldb_private::Type object for
  ///   the type from the index. This allows type parsing to be as efficient as
  ///   possible and only realize the types that match the query.
  bool
  ContextMatches(llvm::ArrayRef<lldb_private::CompilerContext> context) const;

  /// Get the type basename to use when searching the type indexes in each
  /// SymbolFile object.
  ///
  /// Debug information indexes often contain indexes that track the basename
  /// of types only, not a fully qualified path. This allows the indexes to be
  /// smaller and allows for efficient lookups.
  ///
  /// \returns
  ///   The type basename to use when doing lookups as a constant string.
  ConstString GetTypeBasename() const;

  /// Returns true if any matching languages have been specified in this type
  /// matching object.
  bool HasLanguage() const { return m_languages.has_value(); }

  /// Add a language family to the list of languages that should produce a
  /// match.
  void AddLanguage(lldb::LanguageType language);

  /// Check if the language matches any languages that have been added to this
  /// match object.
  ///
  /// \returns
  ///   True if no language have been specified, or if some language have been
  ///   added using AddLanguage(...) and they match. False otherwise.
  bool LanguageMatches(lldb::LanguageType language) const;

  bool GetExactMatch() const { return (m_options & e_exact_match) != 0; }
  /// The \a m_context can be used in two ways: normal types searching with
  /// the context containing a stanadard declaration context for a type, or
  /// with the context being more complete for exact matches in clang modules.
  /// Set this to true if you wish to search for a type in clang module.
  bool GetModuleSearch() const { return (m_options & e_module_search) != 0; }

  /// Returns true if the type query is supposed to find only a single matching
  /// type. Returns false if the type query should find all matches.
  bool GetFindOne() const { return (m_options & e_find_one) != 0; }
  void SetFindOne(bool b) {
    if (b)
      m_options |= e_find_one;
    else
      m_options &= (e_exact_match | e_find_one);
  }

  /// Access the internal compiler context array.
  ///
  /// Clients can use this to populate the context manually.
  std::vector<lldb_private::CompilerContext> &GetContextRef() {
    return m_context;
  }

protected:
  /// A full or partial compiler context array where the parent declaration
  /// contexts appear at the top of the array starting at index zero and the
  /// last entry contains the type and name of the type we are looking for.
  std::vector<lldb_private::CompilerContext> m_context;
  /// An options bitmask that contains enabled options for the type query.
  /// \see TypeQueryOptions.
  TypeQueryOptions m_options;
  /// If this variable has a value, then the language family must match at least
  /// one of the specified languages. If this variable has no value, then the
  /// language of the type doesn't need to match any types that are searched.
  std::optional<LanguageSet> m_languages;
};

/// This class tracks the state and results of a \ref TypeQuery.
///
/// Any mutable state required for type lookups and the results are tracked in
/// this object.
class TypeResults {
public:
  /// Construct a type results object
  TypeResults() = default;

  /// When types that match a TypeQuery are found, this API is used to insert
  /// the matching types.
  ///
  /// \return
  ///   True if the type was added, false if the \a type_sp was already in the
  ///   results.
  bool InsertUnique(const lldb::TypeSP &type_sp);

  /// Check if the type matching has found all of the matches that it needs.
  bool Done(const TypeQuery &query) const;

  /// Check if a SymbolFile object has already been searched by this type match
  /// object.
  ///
  /// This function will add \a sym_file to the set of SymbolFile objects if it
  /// isn't already in the set and return \a false. Returns true if \a sym_file
  /// was already in the set and doesn't need to be searched.
  ///
  /// Any clients that search for types should first check that the symbol file
  /// has not already been searched. If this function returns true, the type
  /// search function should early return to avoid duplicating type searchihng
  /// efforts.
  ///
  /// \param[in] sym_file
  ///   A SymbolFile pointer that will be used to track which symbol files have
  ///   already been searched.
  ///
  /// \returns
  ///   True if the symbol file has been search already, false otherwise.
  bool AlreadySearched(lldb_private::SymbolFile *sym_file);

  /// Access the set of searched symbol files.
  llvm::DenseSet<lldb_private::SymbolFile *> &GetSearchedSymbolFiles() {
    return m_searched_symbol_files;
  }

  lldb::TypeSP GetFirstType() const { return m_type_map.FirstType(); }
  TypeMap &GetTypeMap() { return m_type_map; }
  const TypeMap &GetTypeMap() const { return m_type_map; }

private:
  /// Matching types get added to this map as type search continues.
  TypeMap m_type_map;
  /// This set is used to track and make sure we only perform lookups in a
  /// symbol file one time.
  llvm::DenseSet<lldb_private::SymbolFile *> m_searched_symbol_files;
};

class SymbolFileType : public std::enable_shared_from_this<SymbolFileType>,
                       public UserID {
public:
  SymbolFileType(SymbolFile &symbol_file, lldb::user_id_t uid)
      : UserID(uid), m_symbol_file(symbol_file) {}

  SymbolFileType(SymbolFile &symbol_file, const lldb::TypeSP &type_sp);

  ~SymbolFileType() = default;

  Type *operator->() { return GetType(); }

  Type *GetType();
  SymbolFile &GetSymbolFile() const { return m_symbol_file; }

protected:
  SymbolFile &m_symbol_file;
  lldb::TypeSP m_type_sp;
};

class Type : public std::enable_shared_from_this<Type>, public UserID {
public:
  enum EncodingDataType {
    /// Invalid encoding.
    eEncodingInvalid,
    /// This type is the type whose UID is m_encoding_uid.
    eEncodingIsUID,
    /// This type is the type whose UID is m_encoding_uid with the const
    /// qualifier added.
    eEncodingIsConstUID,
    /// This type is the type whose UID is m_encoding_uid with the restrict
    /// qualifier added.
    eEncodingIsRestrictUID,
    /// This type is the type whose UID is m_encoding_uid with the volatile
    /// qualifier added.
    eEncodingIsVolatileUID,
    /// This type is alias to a type whose UID is m_encoding_uid.
    eEncodingIsTypedefUID,
    /// This type is pointer to a type whose UID is m_encoding_uid.
    eEncodingIsPointerUID,
    /// This type is L value reference to a type whose UID is m_encoding_uid.
    eEncodingIsLValueReferenceUID,
    /// This type is R value reference to a type whose UID is m_encoding_uid.
    eEncodingIsRValueReferenceUID,
    /// This type is the type whose UID is m_encoding_uid as an atomic type.
    eEncodingIsAtomicUID,
    /// This type is the synthetic type whose UID is m_encoding_uid.
    eEncodingIsSyntheticUID
  };

  enum class ResolveState : unsigned char {
    Unresolved = 0,
    Forward = 1,
    Layout = 2,
    Full = 3
  };

  void Dump(Stream *s, bool show_context,
            lldb::DescriptionLevel level = lldb::eDescriptionLevelFull);

  void DumpTypeName(Stream *s);

  /// Since Type instances only keep a "SymbolFile *" internally, other classes
  /// like TypeImpl need make sure the module is still around before playing
  /// with
  /// Type instances. They can store a weak pointer to the Module;
  lldb::ModuleSP GetModule();

  /// GetModule may return module for compile unit's object file.
  /// GetExeModule returns module for executable object file that contains
  /// compile unit where type was actually defined.
  /// GetModule and GetExeModule may return the same value.
  lldb::ModuleSP GetExeModule();

  void GetDescription(Stream *s, lldb::DescriptionLevel level, bool show_name,
                      ExecutionContextScope *exe_scope);

  SymbolFile *GetSymbolFile() { return m_symbol_file; }
  const SymbolFile *GetSymbolFile() const { return m_symbol_file; }

  ConstString GetName();

  ConstString GetBaseName();

  std::optional<uint64_t> GetByteSize(ExecutionContextScope *exe_scope);

  uint32_t GetNumChildren(bool omit_empty_base_classes);

  bool IsAggregateType();

  // Returns if the type is a templated decl. Does not look through typedefs.
  bool IsTemplateType();

  bool IsValidType() { return m_encoding_uid_type != eEncodingInvalid; }

  bool IsTypedef() { return m_encoding_uid_type == eEncodingIsTypedefUID; }

  lldb::TypeSP GetTypedefType();

  ConstString GetName() const { return m_name; }

  ConstString GetQualifiedName();

  bool ReadFromMemory(ExecutionContext *exe_ctx, lldb::addr_t address,
                      AddressType address_type, DataExtractor &data);

  bool WriteToMemory(ExecutionContext *exe_ctx, lldb::addr_t address,
                     AddressType address_type, DataExtractor &data);

  lldb::Format GetFormat();

  lldb::Encoding GetEncoding(uint64_t &count);

  SymbolContextScope *GetSymbolContextScope() { return m_context; }
  const SymbolContextScope *GetSymbolContextScope() const { return m_context; }
  void SetSymbolContextScope(SymbolContextScope *context) {
    m_context = context;
  }

  const lldb_private::Declaration &GetDeclaration() const;

  // Get the clang type, and resolve definitions for any
  // class/struct/union/enum types completely.
  CompilerType GetFullCompilerType();

  // Get the clang type, and resolve definitions enough so that the type could
  // have layout performed. This allows ptrs and refs to
  // class/struct/union/enum types remain forward declarations.
  CompilerType GetLayoutCompilerType();

  // Get the clang type and leave class/struct/union/enum types as forward
  // declarations if they haven't already been fully defined.
  CompilerType GetForwardCompilerType();

  static int Compare(const Type &a, const Type &b);

  // From a fully qualified typename, split the type into the type basename and
  // the remaining type scope (namespaces/classes).
  static bool GetTypeScopeAndBasename(llvm::StringRef name,
                                      llvm::StringRef &scope,
                                      llvm::StringRef &basename,
                                      lldb::TypeClass &type_class);
  void SetEncodingType(Type *encoding_type) { m_encoding_type = encoding_type; }

  uint32_t GetEncodingMask();

  typedef uint32_t Payload;
  /// Return the language-specific payload.
  Payload GetPayload() { return m_payload; }
  /// Return the language-specific payload.
  void SetPayload(Payload opaque_payload) { m_payload = opaque_payload; }

protected:
  ConstString m_name;
  SymbolFile *m_symbol_file = nullptr;
  /// The symbol context in which this type is defined.
  SymbolContextScope *m_context = nullptr;
  Type *m_encoding_type = nullptr;
  lldb::user_id_t m_encoding_uid = LLDB_INVALID_UID;
  EncodingDataType m_encoding_uid_type = eEncodingInvalid;
  uint64_t m_byte_size : 63;
  uint64_t m_byte_size_has_value : 1;
  Declaration m_decl;
  CompilerType m_compiler_type;
  ResolveState m_compiler_type_resolve_state = ResolveState::Unresolved;
  /// Language-specific flags.
  Payload m_payload;

  Type *GetEncodingType();

  bool ResolveCompilerType(ResolveState compiler_type_resolve_state);
private:
  /// Only allow Symbol File to create types, as they should own them by keeping
  /// them in their TypeList. \see SymbolFileCommon::MakeType() reference in the
  /// header documentation here so users will know what function to use if the
  /// get a compile error.
  friend class lldb_private::SymbolFileCommon;

  Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name,
       std::optional<uint64_t> byte_size, SymbolContextScope *context,
       lldb::user_id_t encoding_uid, EncodingDataType encoding_uid_type,
       const Declaration &decl, const CompilerType &compiler_qual_type,
       ResolveState compiler_type_resolve_state, uint32_t opaque_payload = 0);

  // This makes an invalid type.  Used for functions that return a Type when
  // they get an error.
  Type();

  Type(Type &t) = default;

  Type(Type &&t) = default;

  Type &operator=(const Type &t) = default;

  Type &operator=(Type &&t) = default;
};

// the two classes here are used by the public API as a backend to the SBType
// and SBTypeList classes

class TypeImpl {
public:
  TypeImpl() = default;

  ~TypeImpl() = default;

  TypeImpl(const lldb::TypeSP &type_sp);

  TypeImpl(const CompilerType &compiler_type);

  TypeImpl(const lldb::TypeSP &type_sp, const CompilerType &dynamic);

  TypeImpl(const CompilerType &compiler_type, const CompilerType &dynamic);

  void SetType(const lldb::TypeSP &type_sp);

  void SetType(const CompilerType &compiler_type);

  void SetType(const lldb::TypeSP &type_sp, const CompilerType &dynamic);

  void SetType(const CompilerType &compiler_type, const CompilerType &dynamic);

  bool operator==(const TypeImpl &rhs) const;

  bool operator!=(const TypeImpl &rhs) const;

  bool IsValid() const;

  explicit operator bool() const;

  void Clear();

  lldb::ModuleSP GetModule() const;

  ConstString GetName() const;

  ConstString GetDisplayTypeName() const;

  TypeImpl GetPointerType() const;

  TypeImpl GetPointeeType() const;

  TypeImpl GetReferenceType() const;

  TypeImpl GetTypedefedType() const;

  TypeImpl GetDereferencedType() const;

  TypeImpl GetUnqualifiedType() const;

  TypeImpl GetCanonicalType() const;

  CompilerType GetCompilerType(bool prefer_dynamic);

  CompilerType::TypeSystemSPWrapper GetTypeSystem(bool prefer_dynamic);

  bool GetDescription(lldb_private::Stream &strm,
                      lldb::DescriptionLevel description_level);

  CompilerType FindDirectNestedType(llvm::StringRef name);

private:
  bool CheckModule(lldb::ModuleSP &module_sp) const;
  bool CheckExeModule(lldb::ModuleSP &module_sp) const;
  bool CheckModuleCommon(const lldb::ModuleWP &input_module_wp,
                         lldb::ModuleSP &module_sp) const;

  lldb::ModuleWP m_module_wp;
  lldb::ModuleWP m_exe_module_wp;
  CompilerType m_static_type;
  CompilerType m_dynamic_type;
};

class TypeListImpl {
public:
  TypeListImpl() = default;

  void Append(const lldb::TypeImplSP &type) { m_content.push_back(type); }

  class AppendVisitor {
  public:
    AppendVisitor(TypeListImpl &type_list) : m_type_list(type_list) {}

    void operator()(const lldb::TypeImplSP &type) { m_type_list.Append(type); }

  private:
    TypeListImpl &m_type_list;
  };

  void Append(const lldb_private::TypeList &type_list);

  lldb::TypeImplSP GetTypeAtIndex(size_t idx) {
    lldb::TypeImplSP type_sp;
    if (idx < GetSize())
      type_sp = m_content[idx];
    return type_sp;
  }

  size_t GetSize() { return m_content.size(); }

private:
  std::vector<lldb::TypeImplSP> m_content;
};

class TypeMemberImpl {
public:
  TypeMemberImpl() = default;

  TypeMemberImpl(const lldb::TypeImplSP &type_impl_sp, uint64_t bit_offset,
                 ConstString name, uint32_t bitfield_bit_size = 0,
                 bool is_bitfield = false)
      : m_type_impl_sp(type_impl_sp), m_bit_offset(bit_offset), m_name(name),
        m_bitfield_bit_size(bitfield_bit_size), m_is_bitfield(is_bitfield) {}

  TypeMemberImpl(const lldb::TypeImplSP &type_impl_sp, uint64_t bit_offset)
      : m_type_impl_sp(type_impl_sp), m_bit_offset(bit_offset),
        m_bitfield_bit_size(0), m_is_bitfield(false) {
    if (m_type_impl_sp)
      m_name = m_type_impl_sp->GetName();
  }

  const lldb::TypeImplSP &GetTypeImpl() { return m_type_impl_sp; }

  ConstString GetName() const { return m_name; }

  uint64_t GetBitOffset() const { return m_bit_offset; }

  uint32_t GetBitfieldBitSize() const { return m_bitfield_bit_size; }

  void SetBitfieldBitSize(uint32_t bitfield_bit_size) {
    m_bitfield_bit_size = bitfield_bit_size;
  }

  bool GetIsBitfield() const { return m_is_bitfield; }

  void SetIsBitfield(bool is_bitfield) { m_is_bitfield = is_bitfield; }

protected:
  lldb::TypeImplSP m_type_impl_sp;
  uint64_t m_bit_offset = 0;
  ConstString m_name;
  uint32_t m_bitfield_bit_size = 0; // Bit size for bitfield members only
  bool m_is_bitfield = false;
};

///
/// Sometimes you can find the name of the type corresponding to an object, but
/// we don't have debug
/// information for it.  If that is the case, you can return one of these
/// objects, and then if it
/// has a full type, you can use that, but if not at least you can print the
/// name for informational
/// purposes.
///

class TypeAndOrName {
public:
  TypeAndOrName() = default;
  TypeAndOrName(lldb::TypeSP &type_sp);
  TypeAndOrName(const CompilerType &compiler_type);
  TypeAndOrName(const char *type_str);
  TypeAndOrName(ConstString &type_const_string);

  bool operator==(const TypeAndOrName &other) const;

  bool operator!=(const TypeAndOrName &other) const;

  ConstString GetName() const;

  CompilerType GetCompilerType() const { return m_compiler_type; }

  void SetName(ConstString type_name);

  void SetName(const char *type_name_cstr);

  void SetName(llvm::StringRef name);

  void SetTypeSP(lldb::TypeSP type_sp);

  void SetCompilerType(CompilerType compiler_type);

  bool IsEmpty() const;

  bool HasName() const;

  bool HasCompilerType() const;

  bool HasType() const { return HasCompilerType(); }

  void Clear();

  explicit operator bool() { return !IsEmpty(); }

private:
  CompilerType m_compiler_type;
  ConstString m_type_name;
};

class TypeMemberFunctionImpl {
public:
  TypeMemberFunctionImpl() = default;

  TypeMemberFunctionImpl(const CompilerType &type, const CompilerDecl &decl,
                         const std::string &name,
                         const lldb::MemberFunctionKind &kind)
      : m_type(type), m_decl(decl), m_name(name), m_kind(kind) {}

  bool IsValid();

  ConstString GetName() const;

  ConstString GetMangledName() const;

  CompilerType GetType() const;

  CompilerType GetReturnType() const;

  size_t GetNumArguments() const;

  CompilerType GetArgumentAtIndex(size_t idx) const;

  lldb::MemberFunctionKind GetKind() const;

  bool GetDescription(Stream &stream);

protected:
  std::string GetPrintableTypeName();

private:
  CompilerType m_type;
  CompilerDecl m_decl;
  ConstString m_name;
  lldb::MemberFunctionKind m_kind = lldb::eMemberFunctionKindUnknown;
};

class TypeEnumMemberImpl {
public:
  TypeEnumMemberImpl() : m_name("<invalid>") {}

  TypeEnumMemberImpl(const lldb::TypeImplSP &integer_type_sp, ConstString name,
                     const llvm::APSInt &value);

  TypeEnumMemberImpl(const TypeEnumMemberImpl &rhs) = default;

  TypeEnumMemberImpl &operator=(const TypeEnumMemberImpl &rhs);

  bool IsValid() { return m_valid; }

  ConstString GetName() const { return m_name; }

  const lldb::TypeImplSP &GetIntegerType() const { return m_integer_type_sp; }

  uint64_t GetValueAsUnsigned() const { return m_value.getZExtValue(); }

  int64_t GetValueAsSigned() const { return m_value.getSExtValue(); }

protected:
  lldb::TypeImplSP m_integer_type_sp;
  ConstString m_name;
  llvm::APSInt m_value;
  bool m_valid = false;
};

class TypeEnumMemberListImpl {
public:
  TypeEnumMemberListImpl() = default;

  void Append(const lldb::TypeEnumMemberImplSP &type) {
    m_content.push_back(type);
  }

  void Append(const lldb_private::TypeEnumMemberListImpl &type_list);

  lldb::TypeEnumMemberImplSP GetTypeEnumMemberAtIndex(size_t idx) {
    lldb::TypeEnumMemberImplSP enum_member;
    if (idx < GetSize())
      enum_member = m_content[idx];
    return enum_member;
  }

  size_t GetSize() { return m_content.size(); }

private:
  std::vector<lldb::TypeEnumMemberImplSP> m_content;
};

} // namespace lldb_private

#endif // LLDB_SYMBOL_TYPE_H