1 //===-- ClangASTImporter.h --------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
10 #define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
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"
25 #include "lldb/Host/FileSystem.h"
26 #include "lldb/Symbol/CompilerDeclContext.h"
27 #include "lldb/Utility/LLDBAssert.h"
28 #include "lldb/lldb-types.h"
30 #include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
32 #include "llvm/ADT/DenseMap.h"
34 namespace lldb_private
{
36 class ClangASTMetadata
;
37 class TypeSystemClang
;
39 /// Manages and observes all Clang AST node importing in LLDB.
41 /// The ClangASTImporter takes care of two things:
43 /// 1. Keeps track of all ASTImporter instances in LLDB.
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
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.
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
{
68 LayoutInfo() = default;
69 typedef llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
>
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
;
80 : m_file_manager(clang::FileSystemOptions(),
81 FileSystem::Instance().GetVirtualFileSystem()) {}
83 /// Copies the given type and the respective declarations to the destination
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.
94 /// \see ClangASTImporter::DeportType
95 CompilerType
CopyType(TypeSystemClang
&dst
, const CompilerType
&src_type
);
97 /// \see ClangASTImporter::CopyType
98 clang::Decl
*CopyDecl(clang::ASTContext
*dst_ctx
, clang::Decl
*decl
);
100 /// Copies the given type and the respective declarations to the destination
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
);
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
);
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.
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
);
122 bool LayoutRecordType(
123 const clang::RecordDecl
*record_decl
, uint64_t &bit_size
,
125 llvm::DenseMap
<const clang::FieldDecl
*, uint64_t> &field_offsets
,
126 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
>
128 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
>
131 /// If \ref record has a valid origin, this function copies that
132 /// origin's layout into this ClangASTImporter instance.
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.
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
>
149 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
>
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
157 /// \see ClangASTImporter::Import
158 bool CanImport(const CompilerType
&type
);
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).
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.
167 /// \see ClangASTImporter::Import
168 bool Import(const CompilerType
&type
);
170 bool CompleteType(const CompilerType
&compiler_type
);
172 bool CompleteTagDecl(clang::TagDecl
*decl
);
174 bool CompleteTagDeclWithOrigin(clang::TagDecl
*decl
, clang::TagDecl
*origin
);
176 bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl
*interface_decl
);
178 bool CompleteAndFetchChildren(clang::QualType type
);
180 bool RequireCompleteType(clang::QualType type
);
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.
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
);
192 std::optional
<ClangASTMetadata
> GetDeclMetadata(const clang::Decl
*decl
);
198 typedef std::pair
<lldb::ModuleSP
, CompilerDeclContext
> NamespaceMapItem
;
199 typedef std::vector
<NamespaceMapItem
> NamespaceMap
;
200 typedef std::shared_ptr
<NamespaceMap
> NamespaceMapSP
;
202 void RegisterNamespaceMap(const clang::NamespaceDecl
*decl
,
203 NamespaceMapSP
&namespace_map
);
205 NamespaceMapSP
GetNamespaceMap(const clang::NamespaceDecl
*decl
);
207 void BuildNamespaceMap(const clang::NamespaceDecl
*decl
);
210 // Completers for maps
215 virtual ~MapCompleter();
217 virtual void CompleteNamespaceMap(NamespaceMapSP
&namespace_map
,
219 NamespaceMapSP
&parent_map
) const = 0;
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
);
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
;
231 context_md
= context_md_iter
->second
;
234 context_md
->m_map_completer
= &completer
;
237 void ForgetDestination(clang::ASTContext
*dst_ctx
);
238 void ForgetSource(clang::ASTContext
*dst_ctx
, clang::ASTContext
*src_ctx
);
241 DeclOrigin() = default;
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
);
249 DeclOrigin(const DeclOrigin
&rhs
) {
254 void operator=(const DeclOrigin
&rhs
) {
259 bool Valid() const { return (ctx
!= nullptr || decl
!= nullptr); }
261 clang::ASTContext
*ctx
= nullptr;
262 clang::Decl
*decl
= nullptr;
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;
273 /// ASTImporter that intercepts and records the import process of the
274 /// underlying ASTImporter.
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.
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
);
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;
314 CxxModuleScope(ASTImporterDelegate
&delegate
, clang::ASTContext
*dst_ctx
)
315 : m_delegate(delegate
) {
316 // If the delegate doesn't have a CxxModuleHandler yet, create one
318 if (!delegate
.m_std_handler
) {
319 m_handler
= CxxModuleHandler(delegate
, dst_ctx
);
321 delegate
.m_std_handler
= &m_handler
;
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;
333 void ImportDefinitionTo(clang::Decl
*to
, clang::Decl
*from
);
335 void Imported(clang::Decl
*from
, clang::Decl
*to
) override
;
337 clang::Decl
*GetOriginalDecl(clang::Decl
*To
) override
;
339 void SetImportListener(NewDeclListener
*listener
) {
340 assert(m_new_decl_listener
== nullptr && "Already attached a listener?");
341 m_new_decl_listener
= listener
;
343 void RemoveImportListener() { m_new_decl_listener
= nullptr; }
346 llvm::Expected
<clang::Decl
*> ImportImpl(clang::Decl
*From
) override
;
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;
361 typedef std::shared_ptr
<ASTImporterDelegate
> ImporterDelegateSP
;
362 typedef llvm::DenseMap
<clang::ASTContext
*, ImporterDelegateSP
> DelegateMap
;
363 typedef llvm::DenseMap
<const clang::NamespaceDecl
*, NamespaceMapSP
>
366 class ASTContextMetadata
{
367 typedef llvm::DenseMap
<const clang::Decl
*, DeclOrigin
> OriginMap
;
370 ASTContextMetadata(clang::ASTContext
*dst_ctx
) : m_dst_ctx(dst_ctx
) {}
372 clang::ASTContext
*m_dst_ctx
;
373 DelegateMap m_delegates
;
375 NamespaceMetaMap m_namespace_maps
;
376 MapCompleter
*m_map_completer
= nullptr;
378 /// Sets the DeclOrigin for the given Decl and overwrites any existing
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
;
391 /// Removes any tracked DeclOrigin for the given decl.
392 void removeOrigin(const clang::Decl
*decl
) { m_origins
.erase(decl
); }
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
++);
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())
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();
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
430 typedef std::shared_ptr
<ASTContextMetadata
> ASTContextMetadataSP
;
431 typedef llvm::DenseMap
<const clang::ASTContext
*, ASTContextMetadataSP
>
434 ContextMetadataMap m_metadata_map
;
436 ASTContextMetadataSP
GetContextMetadata(clang::ASTContext
*dst_ctx
) {
437 ContextMetadataMap::iterator context_md_iter
= m_metadata_map
.find(dst_ctx
);
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
;
445 return context_md_iter
->second
;
448 ASTContextMetadataSP
MaybeGetContextMetadata(clang::ASTContext
*dst_ctx
) {
449 ContextMetadataMap::iterator context_md_iter
= m_metadata_map
.find(dst_ctx
);
451 if (context_md_iter
!= m_metadata_map
.end())
452 return context_md_iter
->second
;
453 return ASTContextMetadataSP();
456 ImporterDelegateSP
GetDelegate(clang::ASTContext
*dst_ctx
,
457 clang::ASTContext
*src_ctx
) {
458 ASTContextMetadataSP context_md
= GetContextMetadata(dst_ctx
);
460 DelegateMap
&delegates
= context_md
->m_delegates
;
461 DelegateMap::iterator delegate_iter
= delegates
.find(src_ctx
);
463 if (delegate_iter
== delegates
.end()) {
464 ImporterDelegateSP delegate
=
465 ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx
, src_ctx
));
466 delegates
[src_ctx
] = delegate
;
469 return delegate_iter
->second
;
472 DeclOrigin
GetDeclOrigin(const clang::Decl
*decl
);
474 clang::FileManager m_file_manager
;
475 typedef llvm::DenseMap
<const clang::RecordDecl
*, LayoutInfo
>
476 RecordDeclToLayoutMap
;
478 RecordDeclToLayoutMap m_record_decl_to_layout_map
;
481 template <class D
> class TaggedASTDecl
{
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
; }
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
));
496 template <class D
= clang::Decl
> class DeclFromParser
;
497 template <class D
= clang::Decl
> class DeclFromUser
;
499 template <class D
> class DeclFromParser
: public TaggedASTDecl
<D
> {
501 DeclFromParser() : TaggedASTDecl
<D
>() {}
502 DeclFromParser(D
*_decl
) : TaggedASTDecl
<D
>(_decl
) {}
504 DeclFromUser
<D
> GetOrigin(ClangASTImporter
&importer
);
507 template <class D
> class DeclFromUser
: public TaggedASTDecl
<D
> {
509 DeclFromUser() : TaggedASTDecl
<D
>() {}
510 DeclFromUser(D
*_decl
) : TaggedASTDecl
<D
>(_decl
) {}
512 DeclFromParser
<D
> Import(clang::ASTContext
*dest_ctx
,
513 ClangASTImporter
&importer
);
517 DeclFromUser
<D
> DeclFromParser
<D
>::GetOrigin(ClangASTImporter
&importer
) {
518 ClangASTImporter::DeclOrigin origin
= importer
.GetDeclOrigin(this->decl
);
520 return DeclFromUser
<D
>();
521 return DeclFromUser
<D
>(llvm::dyn_cast
<D
>(origin
.decl
));
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
));
533 } // namespace lldb_private
535 #endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H