Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
39653 views
1
//===-- ClangASTImporter.h --------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
10
#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
11
12
#include <map>
13
#include <memory>
14
#include <set>
15
#include <vector>
16
17
#include "clang/AST/ASTContext.h"
18
#include "clang/AST/ASTImporter.h"
19
#include "clang/AST/CharUnits.h"
20
#include "clang/AST/Decl.h"
21
#include "clang/AST/DeclCXX.h"
22
#include "clang/Basic/FileManager.h"
23
#include "clang/Basic/FileSystemOptions.h"
24
25
#include "lldb/Host/FileSystem.h"
26
#include "lldb/Symbol/CompilerDeclContext.h"
27
#include "lldb/Utility/LLDBAssert.h"
28
#include "lldb/lldb-types.h"
29
30
#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
31
32
#include "llvm/ADT/DenseMap.h"
33
34
namespace lldb_private {
35
36
class ClangASTMetadata;
37
class TypeSystemClang;
38
39
/// Manages and observes all Clang AST node importing in LLDB.
40
///
41
/// The ClangASTImporter takes care of two things:
42
///
43
/// 1. Keeps track of all ASTImporter instances in LLDB.
44
///
45
/// Clang's ASTImporter takes care of importing types from one ASTContext to
46
/// another. This class expands this concept by allowing copying from several
47
/// ASTContext instances to several other ASTContext instances. Instead of
48
/// constructing a new ASTImporter manually to copy over a type/decl, this class
49
/// can be asked to do this. It will construct a ASTImporter for the caller (and
50
/// will cache the ASTImporter instance for later use) and then perform the
51
/// import.
52
///
53
/// This mainly prevents that a caller might construct several ASTImporter
54
/// instances for the same source/target ASTContext combination. As the
55
/// ASTImporter has an internal state that keeps track of already imported
56
/// declarations and so on, using only one ASTImporter instance is more
57
/// efficient and less error-prone than using multiple.
58
///
59
/// 2. Keeps track of from where declarations were imported (origin-tracking).
60
/// The ASTImporter instances in this class usually only performa a minimal
61
/// import, i.e., only a shallow copy is made that is filled out on demand
62
/// when more information is requested later on. This requires record-keeping
63
/// of where any shallow clone originally came from so that the right original
64
/// declaration can be found and used as the source of any missing information.
65
class ClangASTImporter {
66
public:
67
struct LayoutInfo {
68
LayoutInfo() = default;
69
typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
70
OffsetMap;
71
72
uint64_t bit_size = 0;
73
uint64_t alignment = 0;
74
llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
75
OffsetMap base_offsets;
76
OffsetMap vbase_offsets;
77
};
78
79
ClangASTImporter()
80
: m_file_manager(clang::FileSystemOptions(),
81
FileSystem::Instance().GetVirtualFileSystem()) {}
82
83
/// Copies the given type and the respective declarations to the destination
84
/// type system.
85
///
86
/// This function does a shallow copy and requires that the target AST
87
/// has an ExternalASTSource which queries this ClangASTImporter instance
88
/// for any additional information that is maybe lacking in the shallow copy.
89
/// This also means that the type system of src_type can *not* be deleted
90
/// after this function has been called. If you need to delete the source
91
/// type system you either need to delete the destination type system first
92
/// or use \ref ClangASTImporter::DeportType.
93
///
94
/// \see ClangASTImporter::DeportType
95
CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type);
96
97
/// \see ClangASTImporter::CopyType
98
clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
99
100
/// Copies the given type and the respective declarations to the destination
101
/// type system.
102
///
103
/// Unlike CopyType this function ensures that types/declarations which are
104
/// originally from the AST of src_type are fully copied over. The type
105
/// system of src_type can safely be deleted after calling this function.
106
/// \see ClangASTImporter::CopyType
107
CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type);
108
109
/// Copies the given decl to the destination type system.
110
/// \see ClangASTImporter::DeportType
111
clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
112
113
/// Sets the layout for the given RecordDecl. The layout will later be
114
/// used by Clang's during code generation. Not calling this function for
115
/// a RecordDecl will cause that Clang's codegen tries to layout the
116
/// record by itself.
117
///
118
/// \param decl The RecordDecl to set the layout for.
119
/// \param layout The layout for the record.
120
void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout);
121
122
bool LayoutRecordType(
123
const clang::RecordDecl *record_decl, uint64_t &bit_size,
124
uint64_t &alignment,
125
llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
126
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
127
&base_offsets,
128
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
129
&vbase_offsets);
130
131
/// If \ref record has a valid origin, this function copies that
132
/// origin's layout into this ClangASTImporter instance.
133
///
134
/// \param[in] record The decl whose layout we're calculating.
135
/// \param[out] size Size of \ref record in bytes.
136
/// \param[out] alignment Alignment of \ref record in bytes.
137
/// \param[out] field_offsets Offsets of fields of \ref record.
138
/// \param[out] base_offsets Offsets of base classes of \ref record.
139
/// \param[out] vbase_offsets Offsets of virtual base classes of \ref record.
140
///
141
/// \returns Returns 'false' if no valid origin was found for \ref record or
142
/// this function failed to import the layout from the origin. Otherwise,
143
/// returns 'true' and the offsets/size/alignment are valid for use.
144
bool importRecordLayoutFromOrigin(
145
const clang::RecordDecl *record, uint64_t &size, uint64_t &alignment,
146
llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
147
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
148
&base_offsets,
149
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
150
&vbase_offsets);
151
152
/// Returns true iff the given type was copied from another TypeSystemClang
153
/// and the original type in this other TypeSystemClang might contain
154
/// additional information (e.g., the definition of a 'class' type) that could
155
/// be imported.
156
///
157
/// \see ClangASTImporter::Import
158
bool CanImport(const CompilerType &type);
159
160
/// If the given type was copied from another TypeSystemClang then copy over
161
/// all missing information (e.g., the definition of a 'class' type).
162
///
163
/// \return True iff an original type in another TypeSystemClang was found.
164
/// Note: Does *not* return false if an original type was found but
165
/// no information was imported over.
166
///
167
/// \see ClangASTImporter::Import
168
bool Import(const CompilerType &type);
169
170
bool CompleteType(const CompilerType &compiler_type);
171
172
bool CompleteTagDecl(clang::TagDecl *decl);
173
174
bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin);
175
176
bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl);
177
178
bool CompleteAndFetchChildren(clang::QualType type);
179
180
bool RequireCompleteType(clang::QualType type);
181
182
/// Updates the internal origin-tracking information so that the given
183
/// 'original' decl is from now on used to import additional information
184
/// into the given decl.
185
///
186
/// Usually the origin-tracking in the ClangASTImporter is automatically
187
/// updated when a declaration is imported, so the only valid reason to ever
188
/// call this is if there is a 'better' original decl and the target decl
189
/// is only a shallow clone that lacks any contents.
190
void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl);
191
192
ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl);
193
194
//
195
// Namespace maps
196
//
197
198
typedef std::pair<lldb::ModuleSP, CompilerDeclContext> NamespaceMapItem;
199
typedef std::vector<NamespaceMapItem> NamespaceMap;
200
typedef std::shared_ptr<NamespaceMap> NamespaceMapSP;
201
202
void RegisterNamespaceMap(const clang::NamespaceDecl *decl,
203
NamespaceMapSP &namespace_map);
204
205
NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl);
206
207
void BuildNamespaceMap(const clang::NamespaceDecl *decl);
208
209
//
210
// Completers for maps
211
//
212
213
class MapCompleter {
214
public:
215
virtual ~MapCompleter();
216
217
virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map,
218
ConstString name,
219
NamespaceMapSP &parent_map) const = 0;
220
};
221
222
void InstallMapCompleter(clang::ASTContext *dst_ctx,
223
MapCompleter &completer) {
224
ASTContextMetadataSP context_md;
225
ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
226
227
if (context_md_iter == m_metadata_map.end()) {
228
context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
229
m_metadata_map[dst_ctx] = context_md;
230
} else {
231
context_md = context_md_iter->second;
232
}
233
234
context_md->m_map_completer = &completer;
235
}
236
237
void ForgetDestination(clang::ASTContext *dst_ctx);
238
void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx);
239
240
struct DeclOrigin {
241
DeclOrigin() = default;
242
243
DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl)
244
: ctx(_ctx), decl(_decl) {
245
// The decl has to be in its associated ASTContext.
246
assert(_decl == nullptr || &_decl->getASTContext() == _ctx);
247
}
248
249
DeclOrigin(const DeclOrigin &rhs) {
250
ctx = rhs.ctx;
251
decl = rhs.decl;
252
}
253
254
void operator=(const DeclOrigin &rhs) {
255
ctx = rhs.ctx;
256
decl = rhs.decl;
257
}
258
259
bool Valid() const { return (ctx != nullptr || decl != nullptr); }
260
261
clang::ASTContext *ctx = nullptr;
262
clang::Decl *decl = nullptr;
263
};
264
265
/// Listener interface used by the ASTImporterDelegate to inform other code
266
/// about decls that have been imported the first time.
267
struct NewDeclListener {
268
virtual ~NewDeclListener() = default;
269
/// A decl has been imported for the first time.
270
virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0;
271
};
272
273
/// ASTImporter that intercepts and records the import process of the
274
/// underlying ASTImporter.
275
///
276
/// This class updates the map from declarations to their original
277
/// declarations and can record declarations that have been imported in a
278
/// certain interval.
279
///
280
/// When intercepting a declaration import, the ASTImporterDelegate uses the
281
/// CxxModuleHandler to replace any missing or malformed declarations with
282
/// their counterpart from a C++ module.
283
struct ASTImporterDelegate : public clang::ASTImporter {
284
ASTImporterDelegate(ClangASTImporter &main, clang::ASTContext *target_ctx,
285
clang::ASTContext *source_ctx)
286
: clang::ASTImporter(*target_ctx, main.m_file_manager, *source_ctx,
287
main.m_file_manager, true /*minimal*/),
288
m_main(main), m_source_ctx(source_ctx) {
289
// Target and source ASTContext shouldn't be identical. Importing AST
290
// nodes within the same AST doesn't make any sense as the whole idea
291
// is to import them to a different AST.
292
lldbassert(target_ctx != source_ctx && "Can't import into itself");
293
// This is always doing a minimal import of any declarations. This means
294
// that there has to be an ExternalASTSource in the target ASTContext
295
// (that should implement the callbacks that complete any declarations
296
// on demand). Without an ExternalASTSource, this ASTImporter will just
297
// do a minimal import and the imported declarations won't be completed.
298
assert(target_ctx->getExternalSource() && "Missing ExternalSource");
299
setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal);
300
}
301
302
/// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate
303
/// and deattaches it at the end of the scope. Supports being used multiple
304
/// times on the same ASTImporterDelegate instance in nested scopes.
305
class CxxModuleScope {
306
/// The handler we attach to the ASTImporterDelegate.
307
CxxModuleHandler m_handler;
308
/// The ASTImporterDelegate we are supposed to attach the handler to.
309
ASTImporterDelegate &m_delegate;
310
/// True iff we attached the handler to the ASTImporterDelegate.
311
bool m_valid = false;
312
313
public:
314
CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx)
315
: m_delegate(delegate) {
316
// If the delegate doesn't have a CxxModuleHandler yet, create one
317
// and attach it.
318
if (!delegate.m_std_handler) {
319
m_handler = CxxModuleHandler(delegate, dst_ctx);
320
m_valid = true;
321
delegate.m_std_handler = &m_handler;
322
}
323
}
324
~CxxModuleScope() {
325
if (m_valid) {
326
// Make sure no one messed with the handler we placed.
327
assert(m_delegate.m_std_handler == &m_handler);
328
m_delegate.m_std_handler = nullptr;
329
}
330
}
331
};
332
333
void ImportDefinitionTo(clang::Decl *to, clang::Decl *from);
334
335
void Imported(clang::Decl *from, clang::Decl *to) override;
336
337
clang::Decl *GetOriginalDecl(clang::Decl *To) override;
338
339
void SetImportListener(NewDeclListener *listener) {
340
assert(m_new_decl_listener == nullptr && "Already attached a listener?");
341
m_new_decl_listener = listener;
342
}
343
void RemoveImportListener() { m_new_decl_listener = nullptr; }
344
345
protected:
346
llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override;
347
348
private:
349
/// Decls we should ignore when mapping decls back to their original
350
/// ASTContext. Used by the CxxModuleHandler to mark declarations that
351
/// were created from the 'std' C++ module to prevent that the Importer
352
/// tries to sync them with the broken equivalent in the debug info AST.
353
llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore;
354
ClangASTImporter &m_main;
355
clang::ASTContext *m_source_ctx;
356
CxxModuleHandler *m_std_handler = nullptr;
357
/// The currently attached listener.
358
NewDeclListener *m_new_decl_listener = nullptr;
359
};
360
361
typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP;
362
typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap;
363
typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP>
364
NamespaceMetaMap;
365
366
class ASTContextMetadata {
367
typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap;
368
369
public:
370
ASTContextMetadata(clang::ASTContext *dst_ctx) : m_dst_ctx(dst_ctx) {}
371
372
clang::ASTContext *m_dst_ctx;
373
DelegateMap m_delegates;
374
375
NamespaceMetaMap m_namespace_maps;
376
MapCompleter *m_map_completer = nullptr;
377
378
/// Sets the DeclOrigin for the given Decl and overwrites any existing
379
/// DeclOrigin.
380
void setOrigin(const clang::Decl *decl, DeclOrigin origin) {
381
// Setting the origin of any decl to itself (or to a different decl
382
// in the same ASTContext) doesn't make any sense. It will also cause
383
// ASTImporterDelegate::ImportImpl to infinite recurse when trying to find
384
// the 'original' Decl when importing code.
385
assert(&decl->getASTContext() != origin.ctx &&
386
"Trying to set decl origin to its own ASTContext?");
387
assert(decl != origin.decl && "Trying to set decl origin to itself?");
388
m_origins[decl] = origin;
389
}
390
391
/// Removes any tracked DeclOrigin for the given decl.
392
void removeOrigin(const clang::Decl *decl) { m_origins.erase(decl); }
393
394
/// Remove all DeclOrigin entries that point to the given ASTContext.
395
/// Useful when an ASTContext is about to be deleted and all the dangling
396
/// pointers to it need to be removed.
397
void removeOriginsWithContext(clang::ASTContext *ctx) {
398
for (OriginMap::iterator iter = m_origins.begin();
399
iter != m_origins.end();) {
400
if (iter->second.ctx == ctx)
401
m_origins.erase(iter++);
402
else
403
++iter;
404
}
405
}
406
407
/// Returns the DeclOrigin for the given Decl or an invalid DeclOrigin
408
/// instance if there no known DeclOrigin for the given Decl.
409
DeclOrigin getOrigin(const clang::Decl *decl) const {
410
auto iter = m_origins.find(decl);
411
if (iter == m_origins.end())
412
return DeclOrigin();
413
return iter->second;
414
}
415
416
/// Returns true there is a known DeclOrigin for the given Decl.
417
bool hasOrigin(const clang::Decl *decl) const {
418
return getOrigin(decl).Valid();
419
}
420
421
private:
422
/// Maps declarations to the ASTContext/Decl from which they were imported
423
/// from. If a declaration is from an ASTContext which has been deleted
424
/// since the declaration was imported or the declaration wasn't created by
425
/// the ASTImporter, then it doesn't have a DeclOrigin and will not be
426
/// tracked here.
427
OriginMap m_origins;
428
};
429
430
typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP;
431
typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP>
432
ContextMetadataMap;
433
434
ContextMetadataMap m_metadata_map;
435
436
ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) {
437
ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
438
439
if (context_md_iter == m_metadata_map.end()) {
440
ASTContextMetadataSP context_md =
441
ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
442
m_metadata_map[dst_ctx] = context_md;
443
return context_md;
444
}
445
return context_md_iter->second;
446
}
447
448
ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) {
449
ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
450
451
if (context_md_iter != m_metadata_map.end())
452
return context_md_iter->second;
453
return ASTContextMetadataSP();
454
}
455
456
ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx,
457
clang::ASTContext *src_ctx) {
458
ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx);
459
460
DelegateMap &delegates = context_md->m_delegates;
461
DelegateMap::iterator delegate_iter = delegates.find(src_ctx);
462
463
if (delegate_iter == delegates.end()) {
464
ImporterDelegateSP delegate =
465
ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx));
466
delegates[src_ctx] = delegate;
467
return delegate;
468
}
469
return delegate_iter->second;
470
}
471
472
DeclOrigin GetDeclOrigin(const clang::Decl *decl);
473
474
clang::FileManager m_file_manager;
475
typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo>
476
RecordDeclToLayoutMap;
477
478
RecordDeclToLayoutMap m_record_decl_to_layout_map;
479
};
480
481
template <class D> class TaggedASTDecl {
482
public:
483
TaggedASTDecl() : decl(nullptr) {}
484
TaggedASTDecl(D *_decl) : decl(_decl) {}
485
bool IsValid() const { return (decl != nullptr); }
486
bool IsInvalid() const { return !IsValid(); }
487
D *operator->() const { return decl; }
488
D *decl;
489
};
490
491
template <class D2, template <class D> class TD, class D1>
492
TD<D2> DynCast(TD<D1> source) {
493
return TD<D2>(llvm::dyn_cast<D2>(source.decl));
494
}
495
496
template <class D = clang::Decl> class DeclFromParser;
497
template <class D = clang::Decl> class DeclFromUser;
498
499
template <class D> class DeclFromParser : public TaggedASTDecl<D> {
500
public:
501
DeclFromParser() : TaggedASTDecl<D>() {}
502
DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) {}
503
504
DeclFromUser<D> GetOrigin(ClangASTImporter &importer);
505
};
506
507
template <class D> class DeclFromUser : public TaggedASTDecl<D> {
508
public:
509
DeclFromUser() : TaggedASTDecl<D>() {}
510
DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) {}
511
512
DeclFromParser<D> Import(clang::ASTContext *dest_ctx,
513
ClangASTImporter &importer);
514
};
515
516
template <class D>
517
DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTImporter &importer) {
518
ClangASTImporter::DeclOrigin origin = importer.GetDeclOrigin(this->decl);
519
if (!origin.Valid())
520
return DeclFromUser<D>();
521
return DeclFromUser<D>(llvm::dyn_cast<D>(origin.decl));
522
}
523
524
template <class D>
525
DeclFromParser<D> DeclFromUser<D>::Import(clang::ASTContext *dest_ctx,
526
ClangASTImporter &importer) {
527
DeclFromParser<> parser_generic_decl(importer.CopyDecl(dest_ctx, this->decl));
528
if (parser_generic_decl.IsInvalid())
529
return DeclFromParser<D>();
530
return DeclFromParser<D>(llvm::dyn_cast<D>(parser_generic_decl.decl));
531
}
532
533
} // namespace lldb_private
534
535
#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
536
537