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(Val: 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(Val: 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(I: 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(Val: 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(Val: 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(Val: 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(Val: 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(decl: 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(dst_ctx: dest_ctx, decl: 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 | |