]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===--- ExternalASTSource.h - Abstract External AST Interface --*- C++ -*-===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file defines the ExternalASTSource interface, which enables | |
11 | // construction of AST nodes from some external source. | |
12 | // | |
13 | //===----------------------------------------------------------------------===// | |
14 | #ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H | |
15 | #define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H | |
16 | ||
17 | #include "clang/AST/DeclBase.h" | |
18 | #include "clang/AST/CharUnits.h" | |
19 | #include "llvm/ADT/DenseMap.h" | |
20 | ||
21 | namespace clang { | |
22 | ||
23 | class ASTConsumer; | |
24 | class CXXBaseSpecifier; | |
25 | class DeclarationName; | |
26 | class ExternalSemaSource; // layering violation required for downcasting | |
27 | class NamedDecl; | |
28 | class Selector; | |
29 | class Stmt; | |
30 | class TagDecl; | |
31 | ||
32 | /// \brief Enumeration describing the result of loading information from | |
33 | /// an external source. | |
34 | enum ExternalLoadResult { | |
35 | /// \brief Loading the external information has succeeded. | |
36 | ELR_Success, | |
37 | ||
38 | /// \brief Loading the external information has failed. | |
39 | ELR_Failure, | |
40 | ||
41 | /// \brief The external information has already been loaded, and therefore | |
42 | /// no additional processing is required. | |
43 | ELR_AlreadyLoaded | |
44 | }; | |
45 | ||
46 | /// \brief Abstract interface for external sources of AST nodes. | |
47 | /// | |
48 | /// External AST sources provide AST nodes constructed from some | |
49 | /// external source, such as a precompiled header. External AST | |
50 | /// sources can resolve types and declarations from abstract IDs into | |
51 | /// actual type and declaration nodes, and read parts of declaration | |
52 | /// contexts. | |
53 | class ExternalASTSource { | |
54 | /// \brief Whether this AST source also provides information for | |
55 | /// semantic analysis. | |
56 | bool SemaSource; | |
57 | ||
58 | friend class ExternalSemaSource; | |
59 | ||
60 | public: | |
61 | ExternalASTSource() : SemaSource(false) { } | |
62 | ||
63 | virtual ~ExternalASTSource(); | |
64 | ||
65 | /// \brief RAII class for safely pairing a StartedDeserializing call | |
66 | /// with FinishedDeserializing. | |
67 | class Deserializing { | |
68 | ExternalASTSource *Source; | |
69 | public: | |
70 | explicit Deserializing(ExternalASTSource *source) : Source(source) { | |
71 | assert(Source); | |
72 | Source->StartedDeserializing(); | |
73 | } | |
74 | ~Deserializing() { | |
75 | Source->FinishedDeserializing(); | |
76 | } | |
77 | }; | |
78 | ||
79 | /// \brief Resolve a declaration ID into a declaration, potentially | |
80 | /// building a new declaration. | |
81 | /// | |
82 | /// This method only needs to be implemented if the AST source ever | |
83 | /// passes back decl sets as VisibleDeclaration objects. | |
84 | /// | |
85 | /// The default implementation of this method is a no-op. | |
86 | virtual Decl *GetExternalDecl(uint32_t ID); | |
87 | ||
88 | /// \brief Resolve a selector ID into a selector. | |
89 | /// | |
90 | /// This operation only needs to be implemented if the AST source | |
91 | /// returns non-zero for GetNumKnownSelectors(). | |
92 | /// | |
93 | /// The default implementation of this method is a no-op. | |
94 | virtual Selector GetExternalSelector(uint32_t ID); | |
95 | ||
96 | /// \brief Returns the number of selectors known to the external AST | |
97 | /// source. | |
98 | /// | |
99 | /// The default implementation of this method is a no-op. | |
100 | virtual uint32_t GetNumExternalSelectors(); | |
101 | ||
102 | /// \brief Resolve the offset of a statement in the decl stream into | |
103 | /// a statement. | |
104 | /// | |
105 | /// This operation is meant to be used via a LazyOffsetPtr. It only | |
106 | /// needs to be implemented if the AST source uses methods like | |
107 | /// FunctionDecl::setLazyBody when building decls. | |
108 | /// | |
109 | /// The default implementation of this method is a no-op. | |
110 | virtual Stmt *GetExternalDeclStmt(uint64_t Offset); | |
111 | ||
112 | /// \brief Resolve the offset of a set of C++ base specifiers in the decl | |
113 | /// stream into an array of specifiers. | |
114 | /// | |
115 | /// The default implementation of this method is a no-op. | |
116 | virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); | |
117 | ||
118 | /// \brief Finds all declarations with the given name in the | |
119 | /// given context. | |
120 | /// | |
121 | /// Generally the final step of this method is either to call | |
122 | /// SetExternalVisibleDeclsForName or to recursively call lookup on | |
123 | /// the DeclContext after calling SetExternalVisibleDecls. | |
124 | /// | |
125 | /// The default implementation of this method is a no-op. | |
126 | virtual DeclContextLookupResult | |
127 | FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); | |
128 | ||
129 | /// \brief Ensures that the table of all visible declarations inside this | |
130 | /// context is up to date. | |
131 | /// | |
132 | /// The default implementation of this functino is a no-op. | |
133 | virtual void completeVisibleDeclsMap(const DeclContext *DC); | |
134 | ||
135 | /// \brief Finds all declarations lexically contained within the given | |
136 | /// DeclContext, after applying an optional filter predicate. | |
137 | /// | |
138 | /// \param isKindWeWant a predicate function that returns true if the passed | |
139 | /// declaration kind is one we are looking for. If NULL, all declarations | |
140 | /// are returned. | |
141 | /// | |
142 | /// \return an indication of whether the load succeeded or failed. | |
143 | /// | |
144 | /// The default implementation of this method is a no-op. | |
145 | virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, | |
146 | bool (*isKindWeWant)(Decl::Kind), | |
147 | SmallVectorImpl<Decl*> &Result); | |
148 | ||
149 | /// \brief Finds all declarations lexically contained within the given | |
150 | /// DeclContext. | |
151 | /// | |
152 | /// \return true if an error occurred | |
153 | ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, | |
154 | SmallVectorImpl<Decl*> &Result) { | |
155 | return FindExternalLexicalDecls(DC, 0, Result); | |
156 | } | |
157 | ||
158 | template <typename DeclTy> | |
159 | ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC, | |
160 | SmallVectorImpl<Decl*> &Result) { | |
161 | return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result); | |
162 | } | |
163 | ||
164 | /// \brief Get the decls that are contained in a file in the Offset/Length | |
165 | /// range. \p Length can be 0 to indicate a point at \p Offset instead of | |
166 | /// a range. | |
167 | virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length, | |
168 | SmallVectorImpl<Decl *> &Decls) {} | |
169 | ||
170 | /// \brief Gives the external AST source an opportunity to complete | |
171 | /// an incomplete type. | |
172 | virtual void CompleteType(TagDecl *Tag) {} | |
173 | ||
174 | /// \brief Gives the external AST source an opportunity to complete an | |
175 | /// incomplete Objective-C class. | |
176 | /// | |
177 | /// This routine will only be invoked if the "externally completed" bit is | |
178 | /// set on the ObjCInterfaceDecl via the function | |
179 | /// \c ObjCInterfaceDecl::setExternallyCompleted(). | |
180 | virtual void CompleteType(ObjCInterfaceDecl *Class) { } | |
181 | ||
182 | /// \brief Loads comment ranges. | |
183 | virtual void ReadComments() { } | |
184 | ||
185 | /// \brief Notify ExternalASTSource that we started deserialization of | |
186 | /// a decl or type so until FinishedDeserializing is called there may be | |
187 | /// decls that are initializing. Must be paired with FinishedDeserializing. | |
188 | /// | |
189 | /// The default implementation of this method is a no-op. | |
190 | virtual void StartedDeserializing() { } | |
191 | ||
192 | /// \brief Notify ExternalASTSource that we finished the deserialization of | |
193 | /// a decl or type. Must be paired with StartedDeserializing. | |
194 | /// | |
195 | /// The default implementation of this method is a no-op. | |
196 | virtual void FinishedDeserializing() { } | |
197 | ||
198 | /// \brief Function that will be invoked when we begin parsing a new | |
199 | /// translation unit involving this external AST source. | |
200 | /// | |
201 | /// The default implementation of this method is a no-op. | |
202 | virtual void StartTranslationUnit(ASTConsumer *Consumer) { } | |
203 | ||
204 | /// \brief Print any statistics that have been gathered regarding | |
205 | /// the external AST source. | |
206 | /// | |
207 | /// The default implementation of this method is a no-op. | |
208 | virtual void PrintStats(); | |
209 | ||
210 | ||
211 | /// \brief Perform layout on the given record. | |
212 | /// | |
213 | /// This routine allows the external AST source to provide an specific | |
214 | /// layout for a record, overriding the layout that would normally be | |
215 | /// constructed. It is intended for clients who receive specific layout | |
216 | /// details rather than source code (such as LLDB). The client is expected | |
217 | /// to fill in the field offsets, base offsets, virtual base offsets, and | |
218 | /// complete object size. | |
219 | /// | |
220 | /// \param Record The record whose layout is being requested. | |
221 | /// | |
222 | /// \param Size The final size of the record, in bits. | |
223 | /// | |
224 | /// \param Alignment The final alignment of the record, in bits. | |
225 | /// | |
226 | /// \param FieldOffsets The offset of each of the fields within the record, | |
227 | /// expressed in bits. All of the fields must be provided with offsets. | |
228 | /// | |
229 | /// \param BaseOffsets The offset of each of the direct, non-virtual base | |
230 | /// classes. If any bases are not given offsets, the bases will be laid | |
231 | /// out according to the ABI. | |
232 | /// | |
233 | /// \param VirtualBaseOffsets The offset of each of the virtual base classes | |
234 | /// (either direct or not). If any bases are not given offsets, the bases will be laid | |
235 | /// out according to the ABI. | |
236 | /// | |
237 | /// \returns true if the record layout was provided, false otherwise. | |
238 | virtual bool | |
239 | layoutRecordType(const RecordDecl *Record, | |
240 | uint64_t &Size, uint64_t &Alignment, | |
241 | llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, | |
242 | llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, | |
243 | llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets) | |
244 | { | |
245 | return false; | |
246 | } | |
247 | ||
248 | //===--------------------------------------------------------------------===// | |
249 | // Queries for performance analysis. | |
250 | //===--------------------------------------------------------------------===// | |
251 | ||
252 | struct MemoryBufferSizes { | |
253 | size_t malloc_bytes; | |
254 | size_t mmap_bytes; | |
255 | ||
256 | MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes) | |
257 | : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} | |
258 | }; | |
259 | ||
260 | /// Return the amount of memory used by memory buffers, breaking down | |
261 | /// by heap-backed versus mmap'ed memory. | |
262 | MemoryBufferSizes getMemoryBufferSizes() const { | |
263 | MemoryBufferSizes sizes(0, 0); | |
264 | getMemoryBufferSizes(sizes); | |
265 | return sizes; | |
266 | } | |
267 | ||
268 | virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const; | |
269 | ||
270 | protected: | |
271 | static DeclContextLookupResult | |
272 | SetExternalVisibleDeclsForName(const DeclContext *DC, | |
273 | DeclarationName Name, | |
274 | ArrayRef<NamedDecl*> Decls); | |
275 | ||
276 | static DeclContextLookupResult | |
277 | SetNoExternalVisibleDeclsForName(const DeclContext *DC, | |
278 | DeclarationName Name); | |
279 | }; | |
280 | ||
281 | /// \brief A lazy pointer to an AST node (of base type T) that resides | |
282 | /// within an external AST source. | |
283 | /// | |
284 | /// The AST node is identified within the external AST source by a | |
285 | /// 63-bit offset, and can be retrieved via an operation on the | |
286 | /// external AST source itself. | |
287 | template<typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)> | |
288 | struct LazyOffsetPtr { | |
289 | /// \brief Either a pointer to an AST node or the offset within the | |
290 | /// external AST source where the AST node can be found. | |
291 | /// | |
292 | /// If the low bit is clear, a pointer to the AST node. If the low | |
293 | /// bit is set, the upper 63 bits are the offset. | |
294 | mutable uint64_t Ptr; | |
295 | ||
296 | public: | |
297 | LazyOffsetPtr() : Ptr(0) { } | |
298 | ||
299 | explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) { } | |
300 | explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) { | |
301 | assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); | |
302 | if (Offset == 0) | |
303 | Ptr = 0; | |
304 | } | |
305 | ||
306 | LazyOffsetPtr &operator=(T *Ptr) { | |
307 | this->Ptr = reinterpret_cast<uint64_t>(Ptr); | |
308 | return *this; | |
309 | } | |
310 | ||
311 | LazyOffsetPtr &operator=(uint64_t Offset) { | |
312 | assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); | |
313 | if (Offset == 0) | |
314 | Ptr = 0; | |
315 | else | |
316 | Ptr = (Offset << 1) | 0x01; | |
317 | ||
318 | return *this; | |
319 | } | |
320 | ||
321 | /// \brief Whether this pointer is non-NULL. | |
322 | /// | |
323 | /// This operation does not require the AST node to be deserialized. | |
324 | operator bool() const { return Ptr != 0; } | |
325 | ||
326 | /// \brief Whether this pointer is currently stored as an offset. | |
327 | bool isOffset() const { return Ptr & 0x01; } | |
328 | ||
329 | /// \brief Retrieve the pointer to the AST node that this lazy pointer | |
330 | /// | |
331 | /// \param Source the external AST source. | |
332 | /// | |
333 | /// \returns a pointer to the AST node. | |
334 | T* get(ExternalASTSource *Source) const { | |
335 | if (isOffset()) { | |
336 | assert(Source && | |
337 | "Cannot deserialize a lazy pointer without an AST source"); | |
338 | Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1)); | |
339 | } | |
340 | return reinterpret_cast<T*>(Ptr); | |
341 | } | |
342 | }; | |
343 | ||
344 | /// \brief Represents a lazily-loaded vector of data. | |
345 | /// | |
346 | /// The lazily-loaded vector of data contains data that is partially loaded | |
347 | /// from an external source and partially added by local translation. The | |
348 | /// items loaded from the external source are loaded lazily, when needed for | |
349 | /// iteration over the complete vector. | |
350 | template<typename T, typename Source, | |
351 | void (Source::*Loader)(SmallVectorImpl<T>&), | |
352 | unsigned LoadedStorage = 2, unsigned LocalStorage = 4> | |
353 | class LazyVector { | |
354 | SmallVector<T, LoadedStorage> Loaded; | |
355 | SmallVector<T, LocalStorage> Local; | |
356 | ||
357 | public: | |
358 | // Iteration over the elements in the vector. | |
359 | class iterator { | |
360 | LazyVector *Self; | |
361 | ||
362 | /// \brief Position within the vector.. | |
363 | /// | |
364 | /// In a complete iteration, the Position field walks the range [-M, N), | |
365 | /// where negative values are used to indicate elements | |
366 | /// loaded from the external source while non-negative values are used to | |
367 | /// indicate elements added via \c push_back(). | |
368 | /// However, to provide iteration in source order (for, e.g., chained | |
369 | /// precompiled headers), dereferencing the iterator flips the negative | |
370 | /// values (corresponding to loaded entities), so that position -M | |
371 | /// corresponds to element 0 in the loaded entities vector, position -M+1 | |
372 | /// corresponds to element 1 in the loaded entities vector, etc. This | |
373 | /// gives us a reasonably efficient, source-order walk. | |
374 | int Position; | |
375 | ||
376 | friend class LazyVector; | |
377 | ||
378 | public: | |
379 | typedef T value_type; | |
380 | typedef value_type& reference; | |
381 | typedef value_type* pointer; | |
382 | typedef std::random_access_iterator_tag iterator_category; | |
383 | typedef int difference_type; | |
384 | ||
385 | iterator() : Self(0), Position(0) { } | |
386 | ||
387 | iterator(LazyVector *Self, int Position) | |
388 | : Self(Self), Position(Position) { } | |
389 | ||
390 | reference operator*() const { | |
391 | if (Position < 0) | |
392 | return Self->Loaded.end()[Position]; | |
393 | return Self->Local[Position]; | |
394 | } | |
395 | ||
396 | pointer operator->() const { | |
397 | if (Position < 0) | |
398 | return &Self->Loaded.end()[Position]; | |
399 | ||
400 | return &Self->Local[Position]; | |
401 | } | |
402 | ||
403 | reference operator[](difference_type D) { | |
404 | return *(*this + D); | |
405 | } | |
406 | ||
407 | iterator &operator++() { | |
408 | ++Position; | |
409 | return *this; | |
410 | } | |
411 | ||
412 | iterator operator++(int) { | |
413 | iterator Prev(*this); | |
414 | ++Position; | |
415 | return Prev; | |
416 | } | |
417 | ||
418 | iterator &operator--() { | |
419 | --Position; | |
420 | return *this; | |
421 | } | |
422 | ||
423 | iterator operator--(int) { | |
424 | iterator Prev(*this); | |
425 | --Position; | |
426 | return Prev; | |
427 | } | |
428 | ||
429 | friend bool operator==(const iterator &X, const iterator &Y) { | |
430 | return X.Position == Y.Position; | |
431 | } | |
432 | ||
433 | friend bool operator!=(const iterator &X, const iterator &Y) { | |
434 | return X.Position != Y.Position; | |
435 | } | |
436 | ||
437 | friend bool operator<(const iterator &X, const iterator &Y) { | |
438 | return X.Position < Y.Position; | |
439 | } | |
440 | ||
441 | friend bool operator>(const iterator &X, const iterator &Y) { | |
442 | return X.Position > Y.Position; | |
443 | } | |
444 | ||
445 | friend bool operator<=(const iterator &X, const iterator &Y) { | |
446 | return X.Position < Y.Position; | |
447 | } | |
448 | ||
449 | friend bool operator>=(const iterator &X, const iterator &Y) { | |
450 | return X.Position > Y.Position; | |
451 | } | |
452 | ||
453 | friend iterator& operator+=(iterator &X, difference_type D) { | |
454 | X.Position += D; | |
455 | return X; | |
456 | } | |
457 | ||
458 | friend iterator& operator-=(iterator &X, difference_type D) { | |
459 | X.Position -= D; | |
460 | return X; | |
461 | } | |
462 | ||
463 | friend iterator operator+(iterator X, difference_type D) { | |
464 | X.Position += D; | |
465 | return X; | |
466 | } | |
467 | ||
468 | friend iterator operator+(difference_type D, iterator X) { | |
469 | X.Position += D; | |
470 | return X; | |
471 | } | |
472 | ||
473 | friend difference_type operator-(const iterator &X, const iterator &Y) { | |
474 | return X.Position - Y.Position; | |
475 | } | |
476 | ||
477 | friend iterator operator-(iterator X, difference_type D) { | |
478 | X.Position -= D; | |
479 | return X; | |
480 | } | |
481 | }; | |
482 | friend class iterator; | |
483 | ||
484 | iterator begin(Source *source, bool LocalOnly = false) { | |
485 | if (LocalOnly) | |
486 | return iterator(this, 0); | |
487 | ||
488 | if (source) | |
489 | (source->*Loader)(Loaded); | |
490 | return iterator(this, -(int)Loaded.size()); | |
491 | } | |
492 | ||
493 | iterator end() { | |
494 | return iterator(this, Local.size()); | |
495 | } | |
496 | ||
497 | void push_back(const T& LocalValue) { | |
498 | Local.push_back(LocalValue); | |
499 | } | |
500 | ||
501 | void erase(iterator From, iterator To) { | |
502 | if (From.Position < 0 && To.Position < 0) { | |
503 | Loaded.erase(Loaded.end() + From.Position, Loaded.end() + To.Position); | |
504 | return; | |
505 | } | |
506 | ||
507 | if (From.Position < 0) { | |
508 | Loaded.erase(Loaded.end() + From.Position, Loaded.end()); | |
509 | From = begin(0, true); | |
510 | } | |
511 | ||
512 | Local.erase(Local.begin() + From.Position, Local.begin() + To.Position); | |
513 | } | |
514 | }; | |
515 | ||
516 | /// \brief A lazy pointer to a statement. | |
517 | typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt> | |
518 | LazyDeclStmtPtr; | |
519 | ||
520 | /// \brief A lazy pointer to a declaration. | |
521 | typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl> | |
522 | LazyDeclPtr; | |
523 | ||
524 | /// \brief A lazy pointer to a set of CXXBaseSpecifiers. | |
525 | typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t, | |
526 | &ExternalASTSource::GetExternalCXXBaseSpecifiers> | |
527 | LazyCXXBaseSpecifiersPtr; | |
528 | ||
529 | } // end namespace clang | |
530 | ||
531 | #endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H |