Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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(uint32_t 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(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, [](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 ReadComments(); |
||
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(&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)(Ptr >> 1)); |
||
379 | } |
||
380 | return reinterpret_cast<T*>(Ptr); |
||
381 | } |
||
382 | }; |
||
383 | |||
384 | /// A lazy value (of type T) that is within an AST node of type Owner, |
||
385 | /// where the value might change in later generations of the external AST |
||
386 | /// source. |
||
387 | template<typename Owner, typename T, void (ExternalASTSource::*Update)(Owner)> |
||
388 | struct LazyGenerationalUpdatePtr { |
||
389 | /// A cache of the value of this pointer, in the most recent generation in |
||
390 | /// which we queried it. |
||
391 | struct LazyData { |
||
392 | ExternalASTSource *ExternalSource; |
||
393 | uint32_t LastGeneration = 0; |
||
394 | T LastValue; |
||
395 | |||
396 | LazyData(ExternalASTSource *Source, T Value) |
||
397 | : ExternalSource(Source), LastValue(Value) {} |
||
398 | }; |
||
399 | |||
400 | // Our value is represented as simply T if there is no external AST source. |
||
401 | using ValueType = llvm::PointerUnion<T, LazyData*>; |
||
402 | ValueType Value; |
||
403 | |||
404 | LazyGenerationalUpdatePtr(ValueType V) : Value(V) {} |
||
405 | |||
406 | // Defined in ASTContext.h |
||
407 | static ValueType makeValue(const ASTContext &Ctx, T Value); |
||
408 | |||
409 | public: |
||
410 | explicit LazyGenerationalUpdatePtr(const ASTContext &Ctx, T Value = T()) |
||
411 | : Value(makeValue(Ctx, Value)) {} |
||
412 | |||
413 | /// Create a pointer that is not potentially updated by later generations of |
||
414 | /// the external AST source. |
||
415 | enum NotUpdatedTag { NotUpdated }; |
||
416 | LazyGenerationalUpdatePtr(NotUpdatedTag, T Value = T()) |
||
417 | : Value(Value) {} |
||
418 | |||
419 | /// Forcibly set this pointer (which must be lazy) as needing updates. |
||
420 | void markIncomplete() { |
||
421 | Value.template get<LazyData *>()->LastGeneration = 0; |
||
422 | } |
||
423 | |||
424 | /// Set the value of this pointer, in the current generation. |
||
425 | void set(T NewValue) { |
||
426 | if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) { |
||
427 | LazyVal->LastValue = NewValue; |
||
428 | return; |
||
429 | } |
||
430 | Value = NewValue; |
||
431 | } |
||
432 | |||
433 | /// Set the value of this pointer, for this and all future generations. |
||
434 | void setNotUpdated(T NewValue) { Value = NewValue; } |
||
435 | |||
436 | /// Get the value of this pointer, updating its owner if necessary. |
||
437 | T get(Owner O) { |
||
438 | if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) { |
||
439 | if (LazyVal->LastGeneration != LazyVal->ExternalSource->getGeneration()) { |
||
440 | LazyVal->LastGeneration = LazyVal->ExternalSource->getGeneration(); |
||
441 | (LazyVal->ExternalSource->*Update)(O); |
||
442 | } |
||
443 | return LazyVal->LastValue; |
||
444 | } |
||
445 | return Value.template get<T>(); |
||
446 | } |
||
447 | |||
448 | /// Get the most recently computed value of this pointer without updating it. |
||
449 | T getNotUpdated() const { |
||
450 | if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) |
||
451 | return LazyVal->LastValue; |
||
452 | return Value.template get<T>(); |
||
453 | } |
||
454 | |||
455 | void *getOpaqueValue() { return Value.getOpaqueValue(); } |
||
456 | static LazyGenerationalUpdatePtr getFromOpaqueValue(void *Ptr) { |
||
457 | return LazyGenerationalUpdatePtr(ValueType::getFromOpaqueValue(Ptr)); |
||
458 | } |
||
459 | }; |
||
460 | |||
461 | } // namespace clang |
||
462 | |||
463 | namespace llvm { |
||
464 | |||
465 | /// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be |
||
466 | /// placed into a PointerUnion. |
||
467 | template<typename Owner, typename T, |
||
468 | void (clang::ExternalASTSource::*Update)(Owner)> |
||
469 | struct PointerLikeTypeTraits< |
||
470 | clang::LazyGenerationalUpdatePtr<Owner, T, Update>> { |
||
471 | using Ptr = clang::LazyGenerationalUpdatePtr<Owner, T, Update>; |
||
472 | |||
473 | static void *getAsVoidPointer(Ptr P) { return P.getOpaqueValue(); } |
||
474 | static Ptr getFromVoidPointer(void *P) { return Ptr::getFromOpaqueValue(P); } |
||
475 | |||
476 | static constexpr int NumLowBitsAvailable = |
||
477 | PointerLikeTypeTraits<T>::NumLowBitsAvailable - 1; |
||
478 | }; |
||
479 | |||
480 | } // namespace llvm |
||
481 | |||
482 | namespace clang { |
||
483 | |||
484 | /// Represents a lazily-loaded vector of data. |
||
485 | /// |
||
486 | /// The lazily-loaded vector of data contains data that is partially loaded |
||
487 | /// from an external source and partially added by local translation. The |
||
488 | /// items loaded from the external source are loaded lazily, when needed for |
||
489 | /// iteration over the complete vector. |
||
490 | template<typename T, typename Source, |
||
491 | void (Source::*Loader)(SmallVectorImpl<T>&), |
||
492 | unsigned LoadedStorage = 2, unsigned LocalStorage = 4> |
||
493 | class LazyVector { |
||
494 | SmallVector<T, LoadedStorage> Loaded; |
||
495 | SmallVector<T, LocalStorage> Local; |
||
496 | |||
497 | public: |
||
498 | /// Iteration over the elements in the vector. |
||
499 | /// |
||
500 | /// In a complete iteration, the iterator walks the range [-M, N), |
||
501 | /// where negative values are used to indicate elements |
||
502 | /// loaded from the external source while non-negative values are used to |
||
503 | /// indicate elements added via \c push_back(). |
||
504 | /// However, to provide iteration in source order (for, e.g., chained |
||
505 | /// precompiled headers), dereferencing the iterator flips the negative |
||
506 | /// values (corresponding to loaded entities), so that position -M |
||
507 | /// corresponds to element 0 in the loaded entities vector, position -M+1 |
||
508 | /// corresponds to element 1 in the loaded entities vector, etc. This |
||
509 | /// gives us a reasonably efficient, source-order walk. |
||
510 | /// |
||
511 | /// We define this as a wrapping iterator around an int. The |
||
512 | /// iterator_adaptor_base class forwards the iterator methods to basic integer |
||
513 | /// arithmetic. |
||
514 | class iterator |
||
515 | : public llvm::iterator_adaptor_base< |
||
516 | iterator, int, std::random_access_iterator_tag, T, int, T *, T &> { |
||
517 | friend class LazyVector; |
||
518 | |||
519 | LazyVector *Self; |
||
520 | |||
521 | iterator(LazyVector *Self, int Position) |
||
522 | : iterator::iterator_adaptor_base(Position), Self(Self) {} |
||
523 | |||
524 | bool isLoaded() const { return this->I < 0; } |
||
525 | |||
526 | public: |
||
527 | iterator() : iterator(nullptr, 0) {} |
||
528 | |||
529 | typename iterator::reference operator*() const { |
||
530 | if (isLoaded()) |
||
531 | return Self->Loaded.end()[this->I]; |
||
532 | return Self->Local.begin()[this->I]; |
||
533 | } |
||
534 | }; |
||
535 | |||
536 | iterator begin(Source *source, bool LocalOnly = false) { |
||
537 | if (LocalOnly) |
||
538 | return iterator(this, 0); |
||
539 | |||
540 | if (source) |
||
541 | (source->*Loader)(Loaded); |
||
542 | return iterator(this, -(int)Loaded.size()); |
||
543 | } |
||
544 | |||
545 | iterator end() { |
||
546 | return iterator(this, Local.size()); |
||
547 | } |
||
548 | |||
549 | void push_back(const T& LocalValue) { |
||
550 | Local.push_back(LocalValue); |
||
551 | } |
||
552 | |||
553 | void erase(iterator From, iterator To) { |
||
554 | if (From.isLoaded() && To.isLoaded()) { |
||
555 | Loaded.erase(&*From, &*To); |
||
556 | return; |
||
557 | } |
||
558 | |||
559 | if (From.isLoaded()) { |
||
560 | Loaded.erase(&*From, Loaded.end()); |
||
561 | From = begin(nullptr, true); |
||
562 | } |
||
563 | |||
564 | Local.erase(&*From, &*To); |
||
565 | } |
||
566 | }; |
||
567 | |||
568 | /// A lazy pointer to a statement. |
||
569 | using LazyDeclStmtPtr = |
||
570 | LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>; |
||
571 | |||
572 | /// A lazy pointer to a declaration. |
||
573 | using LazyDeclPtr = |
||
574 | LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>; |
||
575 | |||
576 | /// A lazy pointer to a set of CXXCtorInitializers. |
||
577 | using LazyCXXCtorInitializersPtr = |
||
578 | LazyOffsetPtr<CXXCtorInitializer *, uint64_t, |
||
579 | &ExternalASTSource::GetExternalCXXCtorInitializers>; |
||
580 | |||
581 | /// A lazy pointer to a set of CXXBaseSpecifiers. |
||
582 | using LazyCXXBaseSpecifiersPtr = |
||
583 | LazyOffsetPtr<CXXBaseSpecifier, uint64_t, |
||
584 | &ExternalASTSource::GetExternalCXXBaseSpecifiers>; |
||
585 | |||
586 | } // namespace clang |
||
587 | |||
588 | #endif // LLVM_CLANG_AST_EXTERNALASTSOURCE_H |