1 | //===- ExternalASTSource.h - Abstract External AST Interface ----*- 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 | // This file defines the ExternalASTSource interface, which enables |
10 | // construction of AST nodes from some external source. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H |
15 | #define LLVM_CLANG_AST_EXTERNALASTSOURCE_H |
16 | |
17 | #include "clang/AST/CharUnits.h" |
18 | #include "clang/AST/DeclBase.h" |
19 | #include "clang/Basic/LLVM.h" |
20 | #include "llvm/ADT/ArrayRef.h" |
21 | #include "llvm/ADT/DenseMap.h" |
22 | #include "llvm/ADT/IntrusiveRefCntPtr.h" |
23 | #include "llvm/ADT/PointerUnion.h" |
24 | #include "llvm/ADT/STLExtras.h" |
25 | #include "llvm/ADT/SmallVector.h" |
26 | #include "llvm/ADT/iterator.h" |
27 | #include "llvm/Support/PointerLikeTypeTraits.h" |
28 | #include <cassert> |
29 | #include <cstddef> |
30 | #include <cstdint> |
31 | #include <iterator> |
32 | #include <optional> |
33 | #include <utility> |
34 | |
35 | namespace clang { |
36 | |
37 | class ASTConsumer; |
38 | class ASTContext; |
39 | class ASTSourceDescriptor; |
40 | class CXXBaseSpecifier; |
41 | class CXXCtorInitializer; |
42 | class CXXRecordDecl; |
43 | class DeclarationName; |
44 | class FieldDecl; |
45 | class IdentifierInfo; |
46 | class NamedDecl; |
47 | class ObjCInterfaceDecl; |
48 | class RecordDecl; |
49 | class Selector; |
50 | class Stmt; |
51 | class TagDecl; |
52 | |
53 | /// Abstract interface for external sources of AST nodes. |
54 | /// |
55 | /// External AST sources provide AST nodes constructed from some |
56 | /// external source, such as a precompiled header. External AST |
57 | /// sources can resolve types and declarations from abstract IDs into |
58 | /// actual type and declaration nodes, and read parts of declaration |
59 | /// contexts. |
60 | class ExternalASTSource : public RefCountedBase<ExternalASTSource> { |
61 | friend class ExternalSemaSource; |
62 | |
63 | /// Generation number for this external AST source. Must be increased |
64 | /// whenever we might have added new redeclarations for existing decls. |
65 | uint32_t CurrentGeneration = 0; |
66 | |
67 | /// LLVM-style RTTI. |
68 | static char ID; |
69 | |
70 | public: |
71 | ExternalASTSource() = default; |
72 | virtual ~ExternalASTSource(); |
73 | |
74 | /// RAII class for safely pairing a StartedDeserializing call |
75 | /// with FinishedDeserializing. |
76 | class Deserializing { |
77 | ExternalASTSource *Source; |
78 | |
79 | public: |
80 | explicit Deserializing(ExternalASTSource *source) : Source(source) { |
81 | assert(Source); |
82 | Source->StartedDeserializing(); |
83 | } |
84 | |
85 | ~Deserializing() { |
86 | Source->FinishedDeserializing(); |
87 | } |
88 | }; |
89 | |
90 | /// Get the current generation of this AST source. This number |
91 | /// is incremented each time the AST source lazily extends an existing |
92 | /// entity. |
93 | uint32_t getGeneration() const { return CurrentGeneration; } |
94 | |
95 | /// Resolve a declaration ID into a declaration, potentially |
96 | /// building a new declaration. |
97 | /// |
98 | /// This method only needs to be implemented if the AST source ever |
99 | /// passes back decl sets as VisibleDeclaration objects. |
100 | /// |
101 | /// The default implementation of this method is a no-op. |
102 | virtual Decl *GetExternalDecl(GlobalDeclID ID); |
103 | |
104 | /// Resolve a selector ID into a selector. |
105 | /// |
106 | /// This operation only needs to be implemented if the AST source |
107 | /// returns non-zero for GetNumKnownSelectors(). |
108 | /// |
109 | /// The default implementation of this method is a no-op. |
110 | virtual Selector GetExternalSelector(uint32_t ID); |
111 | |
112 | /// Returns the number of selectors known to the external AST |
113 | /// source. |
114 | /// |
115 | /// The default implementation of this method is a no-op. |
116 | virtual uint32_t GetNumExternalSelectors(); |
117 | |
118 | /// Resolve the offset of a statement in the decl stream into |
119 | /// a statement. |
120 | /// |
121 | /// This operation is meant to be used via a LazyOffsetPtr. It only |
122 | /// needs to be implemented if the AST source uses methods like |
123 | /// FunctionDecl::setLazyBody when building decls. |
124 | /// |
125 | /// The default implementation of this method is a no-op. |
126 | virtual Stmt *GetExternalDeclStmt(uint64_t Offset); |
127 | |
128 | /// Resolve the offset of a set of C++ constructor initializers in |
129 | /// the decl stream into an array of initializers. |
130 | /// |
131 | /// The default implementation of this method is a no-op. |
132 | virtual CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset); |
133 | |
134 | /// Resolve the offset of a set of C++ base specifiers in the decl |
135 | /// stream into an array of specifiers. |
136 | /// |
137 | /// The default implementation of this method is a no-op. |
138 | virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); |
139 | |
140 | /// Update an out-of-date identifier. |
141 | virtual void updateOutOfDateIdentifier(const IdentifierInfo &II) {} |
142 | |
143 | /// Find all declarations with the given name in the given context, |
144 | /// and add them to the context by calling SetExternalVisibleDeclsForName |
145 | /// or SetNoExternalVisibleDeclsForName. |
146 | /// \return \c true if any declarations might have been found, \c false if |
147 | /// we definitely have no declarations with tbis name. |
148 | /// |
149 | /// The default implementation of this method is a no-op returning \c false. |
150 | virtual bool |
151 | FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); |
152 | |
153 | /// Ensures that the table of all visible declarations inside this |
154 | /// context is up to date. |
155 | /// |
156 | /// The default implementation of this function is a no-op. |
157 | virtual void completeVisibleDeclsMap(const DeclContext *DC); |
158 | |
159 | /// Retrieve the module that corresponds to the given module ID. |
160 | virtual Module *getModule(unsigned ID) { return nullptr; } |
161 | |
162 | /// Return a descriptor for the corresponding module, if one exists. |
163 | virtual std::optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID); |
164 | |
165 | enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy }; |
166 | |
167 | virtual ExtKind hasExternalDefinitions(const Decl *D); |
168 | |
169 | /// Finds all declarations lexically contained within the given |
170 | /// DeclContext, after applying an optional filter predicate. |
171 | /// |
172 | /// \param IsKindWeWant a predicate function that returns true if the passed |
173 | /// declaration kind is one we are looking for. |
174 | /// |
175 | /// The default implementation of this method is a no-op. |
176 | virtual void |
177 | FindExternalLexicalDecls(const DeclContext *DC, |
178 | llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, |
179 | SmallVectorImpl<Decl *> &Result); |
180 | |
181 | /// Finds all declarations lexically contained within the given |
182 | /// DeclContext. |
183 | void FindExternalLexicalDecls(const DeclContext *DC, |
184 | SmallVectorImpl<Decl *> &Result) { |
185 | FindExternalLexicalDecls(DC, IsKindWeWant: [](Decl::Kind) { return true; }, Result); |
186 | } |
187 | |
188 | /// Get the decls that are contained in a file in the Offset/Length |
189 | /// range. \p Length can be 0 to indicate a point at \p Offset instead of |
190 | /// a range. |
191 | virtual void FindFileRegionDecls(FileID File, unsigned Offset, |
192 | unsigned Length, |
193 | SmallVectorImpl<Decl *> &Decls); |
194 | |
195 | /// Gives the external AST source an opportunity to complete |
196 | /// the redeclaration chain for a declaration. Called each time we |
197 | /// need the most recent declaration of a declaration after the |
198 | /// generation count is incremented. |
199 | virtual void CompleteRedeclChain(const Decl *D); |
200 | |
201 | /// Gives the external AST source an opportunity to complete |
202 | /// an incomplete type. |
203 | virtual void CompleteType(TagDecl *Tag); |
204 | |
205 | /// Gives the external AST source an opportunity to complete an |
206 | /// incomplete Objective-C class. |
207 | /// |
208 | /// This routine will only be invoked if the "externally completed" bit is |
209 | /// set on the ObjCInterfaceDecl via the function |
210 | /// \c ObjCInterfaceDecl::setExternallyCompleted(). |
211 | virtual void CompleteType(ObjCInterfaceDecl *Class); |
212 | |
213 | /// Loads comment ranges. |
214 | virtual void (); |
215 | |
216 | /// Notify ExternalASTSource that we started deserialization of |
217 | /// a decl or type so until FinishedDeserializing is called there may be |
218 | /// decls that are initializing. Must be paired with FinishedDeserializing. |
219 | /// |
220 | /// The default implementation of this method is a no-op. |
221 | virtual void StartedDeserializing(); |
222 | |
223 | /// Notify ExternalASTSource that we finished the deserialization of |
224 | /// a decl or type. Must be paired with StartedDeserializing. |
225 | /// |
226 | /// The default implementation of this method is a no-op. |
227 | virtual void FinishedDeserializing(); |
228 | |
229 | /// Function that will be invoked when we begin parsing a new |
230 | /// translation unit involving this external AST source. |
231 | /// |
232 | /// The default implementation of this method is a no-op. |
233 | virtual void StartTranslationUnit(ASTConsumer *Consumer); |
234 | |
235 | /// Print any statistics that have been gathered regarding |
236 | /// the external AST source. |
237 | /// |
238 | /// The default implementation of this method is a no-op. |
239 | virtual void PrintStats(); |
240 | |
241 | /// Perform layout on the given record. |
242 | /// |
243 | /// This routine allows the external AST source to provide an specific |
244 | /// layout for a record, overriding the layout that would normally be |
245 | /// constructed. It is intended for clients who receive specific layout |
246 | /// details rather than source code (such as LLDB). The client is expected |
247 | /// to fill in the field offsets, base offsets, virtual base offsets, and |
248 | /// complete object size. |
249 | /// |
250 | /// \param Record The record whose layout is being requested. |
251 | /// |
252 | /// \param Size The final size of the record, in bits. |
253 | /// |
254 | /// \param Alignment The final alignment of the record, in bits. |
255 | /// |
256 | /// \param FieldOffsets The offset of each of the fields within the record, |
257 | /// expressed in bits. All of the fields must be provided with offsets. |
258 | /// |
259 | /// \param BaseOffsets The offset of each of the direct, non-virtual base |
260 | /// classes. If any bases are not given offsets, the bases will be laid |
261 | /// out according to the ABI. |
262 | /// |
263 | /// \param VirtualBaseOffsets The offset of each of the virtual base classes |
264 | /// (either direct or not). If any bases are not given offsets, the bases will be laid |
265 | /// out according to the ABI. |
266 | /// |
267 | /// \returns true if the record layout was provided, false otherwise. |
268 | virtual bool layoutRecordType( |
269 | const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, |
270 | llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, |
271 | llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, |
272 | llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets); |
273 | |
274 | //===--------------------------------------------------------------------===// |
275 | // Queries for performance analysis. |
276 | //===--------------------------------------------------------------------===// |
277 | |
278 | struct MemoryBufferSizes { |
279 | size_t malloc_bytes; |
280 | size_t mmap_bytes; |
281 | |
282 | MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes) |
283 | : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} |
284 | }; |
285 | |
286 | /// Return the amount of memory used by memory buffers, breaking down |
287 | /// by heap-backed versus mmap'ed memory. |
288 | MemoryBufferSizes getMemoryBufferSizes() const { |
289 | MemoryBufferSizes sizes(0, 0); |
290 | getMemoryBufferSizes(sizes); |
291 | return sizes; |
292 | } |
293 | |
294 | virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const; |
295 | |
296 | /// LLVM-style RTTI. |
297 | /// \{ |
298 | virtual bool isA(const void *ClassID) const { return ClassID == &ID; } |
299 | static bool classof(const ExternalASTSource *S) { return S->isA(ClassID: &ID); } |
300 | /// \} |
301 | |
302 | protected: |
303 | static DeclContextLookupResult |
304 | SetExternalVisibleDeclsForName(const DeclContext *DC, |
305 | DeclarationName Name, |
306 | ArrayRef<NamedDecl*> Decls); |
307 | |
308 | static DeclContextLookupResult |
309 | SetNoExternalVisibleDeclsForName(const DeclContext *DC, |
310 | DeclarationName Name); |
311 | |
312 | /// Increment the current generation. |
313 | uint32_t incrementGeneration(ASTContext &C); |
314 | }; |
315 | |
316 | /// A lazy pointer to an AST node (of base type T) that resides |
317 | /// within an external AST source. |
318 | /// |
319 | /// The AST node is identified within the external AST source by a |
320 | /// 63-bit offset, and can be retrieved via an operation on the |
321 | /// external AST source itself. |
322 | template<typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)> |
323 | struct LazyOffsetPtr { |
324 | /// Either a pointer to an AST node or the offset within the |
325 | /// external AST source where the AST node can be found. |
326 | /// |
327 | /// If the low bit is clear, a pointer to the AST node. If the low |
328 | /// bit is set, the upper 63 bits are the offset. |
329 | mutable uint64_t Ptr = 0; |
330 | |
331 | public: |
332 | LazyOffsetPtr() = default; |
333 | explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) {} |
334 | |
335 | explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) { |
336 | assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits" ); |
337 | if (Offset == 0) |
338 | Ptr = 0; |
339 | } |
340 | |
341 | LazyOffsetPtr &operator=(T *Ptr) { |
342 | this->Ptr = reinterpret_cast<uint64_t>(Ptr); |
343 | return *this; |
344 | } |
345 | |
346 | LazyOffsetPtr &operator=(uint64_t Offset) { |
347 | assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits" ); |
348 | if (Offset == 0) |
349 | Ptr = 0; |
350 | else |
351 | Ptr = (Offset << 1) | 0x01; |
352 | |
353 | return *this; |
354 | } |
355 | |
356 | /// Whether this pointer is non-NULL. |
357 | /// |
358 | /// This operation does not require the AST node to be deserialized. |
359 | explicit operator bool() const { return Ptr != 0; } |
360 | |
361 | /// Whether this pointer is non-NULL. |
362 | /// |
363 | /// This operation does not require the AST node to be deserialized. |
364 | bool isValid() const { return Ptr != 0; } |
365 | |
366 | /// Whether this pointer is currently stored as an offset. |
367 | bool isOffset() const { return Ptr & 0x01; } |
368 | |
369 | /// Retrieve the pointer to the AST node that this lazy pointer points to. |
370 | /// |
371 | /// \param Source the external AST source. |
372 | /// |
373 | /// \returns a pointer to the AST node. |
374 | T *get(ExternalASTSource *Source) const { |
375 | if (isOffset()) { |
376 | assert(Source && |
377 | "Cannot deserialize a lazy pointer without an AST source" ); |
378 | Ptr = reinterpret_cast<uint64_t>((Source->*Get)(OffsT(Ptr >> 1))); |
379 | } |
380 | return reinterpret_cast<T*>(Ptr); |
381 | } |
382 | |
383 | /// Retrieve the address of the AST node pointer. Deserializes the pointee if |
384 | /// necessary. |
385 | T **getAddressOfPointer(ExternalASTSource *Source) const { |
386 | // Ensure the integer is in pointer form. |
387 | (void)get(Source); |
388 | return reinterpret_cast<T**>(&Ptr); |
389 | } |
390 | }; |
391 | |
392 | /// A lazy value (of type T) that is within an AST node of type Owner, |
393 | /// where the value might change in later generations of the external AST |
394 | /// source. |
395 | template<typename Owner, typename T, void (ExternalASTSource::*Update)(Owner)> |
396 | struct LazyGenerationalUpdatePtr { |
397 | /// A cache of the value of this pointer, in the most recent generation in |
398 | /// which we queried it. |
399 | struct LazyData { |
400 | ExternalASTSource *ExternalSource; |
401 | uint32_t LastGeneration = 0; |
402 | T LastValue; |
403 | |
404 | LazyData(ExternalASTSource *Source, T Value) |
405 | : ExternalSource(Source), LastValue(Value) {} |
406 | }; |
407 | |
408 | // Our value is represented as simply T if there is no external AST source. |
409 | using ValueType = llvm::PointerUnion<T, LazyData*>; |
410 | ValueType Value; |
411 | |
412 | LazyGenerationalUpdatePtr(ValueType V) : Value(V) {} |
413 | |
414 | // Defined in ASTContext.h |
415 | static ValueType makeValue(const ASTContext &Ctx, T Value); |
416 | |
417 | public: |
418 | explicit LazyGenerationalUpdatePtr(const ASTContext &Ctx, T Value = T()) |
419 | : Value(makeValue(Ctx, Value)) {} |
420 | |
421 | /// Create a pointer that is not potentially updated by later generations of |
422 | /// the external AST source. |
423 | enum NotUpdatedTag { NotUpdated }; |
424 | LazyGenerationalUpdatePtr(NotUpdatedTag, T Value = T()) |
425 | : Value(Value) {} |
426 | |
427 | /// Forcibly set this pointer (which must be lazy) as needing updates. |
428 | void markIncomplete() { |
429 | Value.template get<LazyData *>()->LastGeneration = 0; |
430 | } |
431 | |
432 | /// Set the value of this pointer, in the current generation. |
433 | void set(T NewValue) { |
434 | if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) { |
435 | LazyVal->LastValue = NewValue; |
436 | return; |
437 | } |
438 | Value = NewValue; |
439 | } |
440 | |
441 | /// Set the value of this pointer, for this and all future generations. |
442 | void setNotUpdated(T NewValue) { Value = NewValue; } |
443 | |
444 | /// Get the value of this pointer, updating its owner if necessary. |
445 | T get(Owner O) { |
446 | if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) { |
447 | if (LazyVal->LastGeneration != LazyVal->ExternalSource->getGeneration()) { |
448 | LazyVal->LastGeneration = LazyVal->ExternalSource->getGeneration(); |
449 | (LazyVal->ExternalSource->*Update)(O); |
450 | } |
451 | return LazyVal->LastValue; |
452 | } |
453 | return Value.template get<T>(); |
454 | } |
455 | |
456 | /// Get the most recently computed value of this pointer without updating it. |
457 | T getNotUpdated() const { |
458 | if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) |
459 | return LazyVal->LastValue; |
460 | return Value.template get<T>(); |
461 | } |
462 | |
463 | void *getOpaqueValue() { return Value.getOpaqueValue(); } |
464 | static LazyGenerationalUpdatePtr getFromOpaqueValue(void *Ptr) { |
465 | return LazyGenerationalUpdatePtr(ValueType::getFromOpaqueValue(Ptr)); |
466 | } |
467 | }; |
468 | |
469 | } // namespace clang |
470 | |
471 | namespace llvm { |
472 | |
473 | /// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be |
474 | /// placed into a PointerUnion. |
475 | template<typename Owner, typename T, |
476 | void (clang::ExternalASTSource::*Update)(Owner)> |
477 | struct PointerLikeTypeTraits< |
478 | clang::LazyGenerationalUpdatePtr<Owner, T, Update>> { |
479 | using Ptr = clang::LazyGenerationalUpdatePtr<Owner, T, Update>; |
480 | |
481 | static void *getAsVoidPointer(Ptr P) { return P.getOpaqueValue(); } |
482 | static Ptr getFromVoidPointer(void *P) { return Ptr::getFromOpaqueValue(P); } |
483 | |
484 | static constexpr int NumLowBitsAvailable = |
485 | PointerLikeTypeTraits<T>::NumLowBitsAvailable - 1; |
486 | }; |
487 | |
488 | } // namespace llvm |
489 | |
490 | namespace clang { |
491 | |
492 | /// Represents a lazily-loaded vector of data. |
493 | /// |
494 | /// The lazily-loaded vector of data contains data that is partially loaded |
495 | /// from an external source and partially added by local translation. The |
496 | /// items loaded from the external source are loaded lazily, when needed for |
497 | /// iteration over the complete vector. |
498 | template<typename T, typename Source, |
499 | void (Source::*Loader)(SmallVectorImpl<T>&), |
500 | unsigned LoadedStorage = 2, unsigned LocalStorage = 4> |
501 | class LazyVector { |
502 | SmallVector<T, LoadedStorage> Loaded; |
503 | SmallVector<T, LocalStorage> Local; |
504 | |
505 | public: |
506 | /// Iteration over the elements in the vector. |
507 | /// |
508 | /// In a complete iteration, the iterator walks the range [-M, N), |
509 | /// where negative values are used to indicate elements |
510 | /// loaded from the external source while non-negative values are used to |
511 | /// indicate elements added via \c push_back(). |
512 | /// However, to provide iteration in source order (for, e.g., chained |
513 | /// precompiled headers), dereferencing the iterator flips the negative |
514 | /// values (corresponding to loaded entities), so that position -M |
515 | /// corresponds to element 0 in the loaded entities vector, position -M+1 |
516 | /// corresponds to element 1 in the loaded entities vector, etc. This |
517 | /// gives us a reasonably efficient, source-order walk. |
518 | /// |
519 | /// We define this as a wrapping iterator around an int. The |
520 | /// iterator_adaptor_base class forwards the iterator methods to basic integer |
521 | /// arithmetic. |
522 | class iterator |
523 | : public llvm::iterator_adaptor_base< |
524 | iterator, int, std::random_access_iterator_tag, T, int, T *, T &> { |
525 | friend class LazyVector; |
526 | |
527 | LazyVector *Self; |
528 | |
529 | iterator(LazyVector *Self, int Position) |
530 | : iterator::iterator_adaptor_base(Position), Self(Self) {} |
531 | |
532 | bool isLoaded() const { return this->I < 0; } |
533 | |
534 | public: |
535 | iterator() : iterator(nullptr, 0) {} |
536 | |
537 | typename iterator::reference operator*() const { |
538 | if (isLoaded()) |
539 | return Self->Loaded.end()[this->I]; |
540 | return Self->Local.begin()[this->I]; |
541 | } |
542 | }; |
543 | |
544 | iterator begin(Source *source, bool LocalOnly = false) { |
545 | if (LocalOnly) |
546 | return iterator(this, 0); |
547 | |
548 | if (source) |
549 | (source->*Loader)(Loaded); |
550 | return iterator(this, -(int)Loaded.size()); |
551 | } |
552 | |
553 | iterator end() { |
554 | return iterator(this, Local.size()); |
555 | } |
556 | |
557 | void push_back(const T& LocalValue) { |
558 | Local.push_back(LocalValue); |
559 | } |
560 | |
561 | void erase(iterator From, iterator To) { |
562 | if (From.isLoaded() && To.isLoaded()) { |
563 | Loaded.erase(&*From, &*To); |
564 | return; |
565 | } |
566 | |
567 | if (From.isLoaded()) { |
568 | Loaded.erase(&*From, Loaded.end()); |
569 | From = begin(source: nullptr, LocalOnly: true); |
570 | } |
571 | |
572 | Local.erase(&*From, &*To); |
573 | } |
574 | }; |
575 | |
576 | /// A lazy pointer to a statement. |
577 | using LazyDeclStmtPtr = |
578 | LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>; |
579 | |
580 | /// A lazy pointer to a declaration. |
581 | using LazyDeclPtr = |
582 | LazyOffsetPtr<Decl, GlobalDeclID, &ExternalASTSource::GetExternalDecl>; |
583 | |
584 | /// A lazy pointer to a set of CXXCtorInitializers. |
585 | using LazyCXXCtorInitializersPtr = |
586 | LazyOffsetPtr<CXXCtorInitializer *, uint64_t, |
587 | &ExternalASTSource::GetExternalCXXCtorInitializers>; |
588 | |
589 | /// A lazy pointer to a set of CXXBaseSpecifiers. |
590 | using LazyCXXBaseSpecifiersPtr = |
591 | LazyOffsetPtr<CXXBaseSpecifier, uint64_t, |
592 | &ExternalASTSource::GetExternalCXXBaseSpecifiers>; |
593 | |
594 | } // namespace clang |
595 | |
596 | #endif // LLVM_CLANG_AST_EXTERNALASTSOURCE_H |
597 | |