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