blob: 0e5b6ee8aa2e0ce6e40a10f011e40ba94168df79 [file] [log] [blame]
Douglas Gregorc34897d2009-04-09 22:27:44 +00001//===--- PCHReader.cpp - Precompiled Headers Reader -------------*- 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 PCHReader class, which reads a precompiled header.
11//
12//===----------------------------------------------------------------------===//
13#include "clang/Frontend/PCHReader.h"
14#include "clang/Frontend/PCHBitCodes.h"
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/Type.h"
Douglas Gregorab1cef72009-04-10 03:52:48 +000018#include "clang/Lex/Preprocessor.h"
19#include "clang/Basic/SourceManager.h"
20#include "clang/Basic/FileManager.h"
Douglas Gregorc34897d2009-04-09 22:27:44 +000021#include "llvm/Bitcode/BitstreamReader.h"
22#include "llvm/Support/Compiler.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include <algorithm>
25#include <cstdio>
26
27using namespace clang;
28
29//===----------------------------------------------------------------------===//
30// Declaration deserialization
31//===----------------------------------------------------------------------===//
32namespace {
33 class VISIBILITY_HIDDEN PCHDeclReader {
34 PCHReader &Reader;
35 const PCHReader::RecordData &Record;
36 unsigned &Idx;
37
38 public:
39 PCHDeclReader(PCHReader &Reader, const PCHReader::RecordData &Record,
40 unsigned &Idx)
41 : Reader(Reader), Record(Record), Idx(Idx) { }
42
43 void VisitDecl(Decl *D);
44 void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
45 void VisitNamedDecl(NamedDecl *ND);
46 void VisitTypeDecl(TypeDecl *TD);
47 void VisitTypedefDecl(TypedefDecl *TD);
48 void VisitValueDecl(ValueDecl *VD);
49 void VisitVarDecl(VarDecl *VD);
50
51 std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
52 };
53}
54
55void PCHDeclReader::VisitDecl(Decl *D) {
56 D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
57 D->setLexicalDeclContext(
58 cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
59 D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
60 D->setInvalidDecl(Record[Idx++]);
61 // FIXME: hasAttrs
62 D->setImplicit(Record[Idx++]);
63 D->setAccess((AccessSpecifier)Record[Idx++]);
64}
65
66void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
67 VisitDecl(TU);
68}
69
70void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) {
71 VisitDecl(ND);
72 ND->setDeclName(Reader.ReadDeclarationName(Record, Idx));
73}
74
75void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) {
76 VisitNamedDecl(TD);
77 // FIXME: circular dependencies here?
78 TD->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
79}
80
81void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
82 VisitTypeDecl(TD);
83 TD->setUnderlyingType(Reader.GetType(Record[Idx++]));
84}
85
86void PCHDeclReader::VisitValueDecl(ValueDecl *VD) {
87 VisitNamedDecl(VD);
88 VD->setType(Reader.GetType(Record[Idx++]));
89}
90
91void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
92 VisitValueDecl(VD);
93 VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]);
94 VD->setThreadSpecified(Record[Idx++]);
95 VD->setCXXDirectInitializer(Record[Idx++]);
96 VD->setDeclaredInCondition(Record[Idx++]);
97 VD->setPreviousDeclaration(
98 cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
99 VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
100}
101
102std::pair<uint64_t, uint64_t>
103PCHDeclReader::VisitDeclContext(DeclContext *DC) {
104 uint64_t LexicalOffset = Record[Idx++];
105 uint64_t VisibleOffset = 0;
106 if (DC->getPrimaryContext() == DC)
107 VisibleOffset = Record[Idx++];
108 return std::make_pair(LexicalOffset, VisibleOffset);
109}
110
111// FIXME: use the diagnostics machinery
112static bool Error(const char *Str) {
113 std::fprintf(stderr, "%s\n", Str);
114 return true;
115}
116
Douglas Gregorab1cef72009-04-10 03:52:48 +0000117/// \brief Read the source manager block
118bool PCHReader::ReadSourceManagerBlock() {
119 using namespace SrcMgr;
120 if (Stream.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID))
121 return Error("Malformed source manager block record");
122
123 SourceManager &SourceMgr = Context.getSourceManager();
124 RecordData Record;
125 while (true) {
126 unsigned Code = Stream.ReadCode();
127 if (Code == llvm::bitc::END_BLOCK) {
128 if (Stream.ReadBlockEnd())
129 return Error("Error at end of Source Manager block");
130 return false;
131 }
132
133 if (Code == llvm::bitc::ENTER_SUBBLOCK) {
134 // No known subblocks, always skip them.
135 Stream.ReadSubBlockID();
136 if (Stream.SkipBlock())
137 return Error("Malformed block record");
138 continue;
139 }
140
141 if (Code == llvm::bitc::DEFINE_ABBREV) {
142 Stream.ReadAbbrevRecord();
143 continue;
144 }
145
146 // Read a record.
147 const char *BlobStart;
148 unsigned BlobLen;
149 Record.clear();
150 switch (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
151 default: // Default behavior: ignore.
152 break;
153
154 case pch::SM_SLOC_FILE_ENTRY: {
155 // FIXME: We would really like to delay the creation of this
156 // FileEntry until it is actually required, e.g., when producing
157 // a diagnostic with a source location in this file.
158 const FileEntry *File
159 = PP.getFileManager().getFile(BlobStart, BlobStart + BlobLen);
160 // FIXME: Error recovery if file cannot be found.
161 SourceMgr.createFileID(File,
162 SourceLocation::getFromRawEncoding(Record[1]),
163 (CharacteristicKind)Record[2]);
164 break;
165 }
166
167 case pch::SM_SLOC_BUFFER_ENTRY: {
168 const char *Name = BlobStart;
169 unsigned Code = Stream.ReadCode();
170 Record.clear();
171 unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen);
172 assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file");
173 SourceMgr.createFileIDForMemBuffer(
174 llvm::MemoryBuffer::getMemBuffer(BlobStart, BlobStart + BlobLen - 1,
175 Name));
176 break;
177 }
178
179 case pch::SM_SLOC_INSTANTIATION_ENTRY: {
180 SourceLocation SpellingLoc
181 = SourceLocation::getFromRawEncoding(Record[1]);
182 SourceMgr.createInstantiationLoc(
183 SpellingLoc,
184 SourceLocation::getFromRawEncoding(Record[2]),
185 SourceLocation::getFromRawEncoding(Record[3]),
186 Lexer::MeasureTokenLength(SpellingLoc,
187 SourceMgr));
188 break;
189 }
190
191 }
192 }
193}
194
Douglas Gregorc34897d2009-04-09 22:27:44 +0000195bool PCHReader::ReadPCHBlock() {
196 if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID))
197 return Error("Malformed block record");
198
199 // Read all of the records and blocks for the PCH file.
Douglas Gregorac8f2802009-04-10 17:25:41 +0000200 RecordData Record;
Douglas Gregorc34897d2009-04-09 22:27:44 +0000201 while (!Stream.AtEndOfStream()) {
202 unsigned Code = Stream.ReadCode();
203 if (Code == llvm::bitc::END_BLOCK) {
204 if (Stream.ReadBlockEnd())
205 return Error("Error at end of module block");
206 return false;
207 }
208
209 if (Code == llvm::bitc::ENTER_SUBBLOCK) {
210 switch (Stream.ReadSubBlockID()) {
211 case pch::DECLS_BLOCK_ID: // Skip decls block (lazily loaded)
212 case pch::TYPES_BLOCK_ID: // Skip types block (lazily loaded)
213 default: // Skip unknown content.
214 if (Stream.SkipBlock())
215 return Error("Malformed block record");
216 break;
217
Douglas Gregorab1cef72009-04-10 03:52:48 +0000218 case pch::SOURCE_MANAGER_BLOCK_ID:
219 if (ReadSourceManagerBlock())
220 return Error("Malformed source manager block");
221 break;
Douglas Gregorc34897d2009-04-09 22:27:44 +0000222 }
Douglas Gregorac8f2802009-04-10 17:25:41 +0000223 continue;
224 }
225
226 if (Code == llvm::bitc::DEFINE_ABBREV) {
227 Stream.ReadAbbrevRecord();
228 continue;
229 }
230
231 // Read and process a record.
232 Record.clear();
233 switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record)) {
234 default: // Default behavior: ignore.
235 break;
236
237 case pch::TYPE_OFFSET:
238 if (!TypeOffsets.empty())
239 return Error("Duplicate TYPE_OFFSET record in PCH file");
240 TypeOffsets.swap(Record);
241 TypeAlreadyLoaded.resize(TypeOffsets.size(), false);
242 break;
243
244 case pch::DECL_OFFSET:
245 if (!DeclOffsets.empty())
246 return Error("Duplicate DECL_OFFSET record in PCH file");
247 DeclOffsets.swap(Record);
248 DeclAlreadyLoaded.resize(DeclOffsets.size(), false);
249 break;
Douglas Gregorc34897d2009-04-09 22:27:44 +0000250 }
251 }
252
253 return Error("Premature end of bitstream");
254}
255
256PCHReader::~PCHReader() { }
257
258bool PCHReader::ReadPCH(const std::string &FileName) {
259 // Open the PCH file.
260 std::string ErrStr;
261 Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr));
262 if (!Buffer)
263 return Error(ErrStr.c_str());
264
265 // Initialize the stream
266 Stream.init((const unsigned char *)Buffer->getBufferStart(),
267 (const unsigned char *)Buffer->getBufferEnd());
268
269 // Sniff for the signature.
270 if (Stream.Read(8) != 'C' ||
271 Stream.Read(8) != 'P' ||
272 Stream.Read(8) != 'C' ||
273 Stream.Read(8) != 'H')
274 return Error("Not a PCH file");
275
276 // We expect a number of well-defined blocks, though we don't necessarily
277 // need to understand them all.
278 while (!Stream.AtEndOfStream()) {
279 unsigned Code = Stream.ReadCode();
280
281 if (Code != llvm::bitc::ENTER_SUBBLOCK)
282 return Error("Invalid record at top-level");
283
284 unsigned BlockID = Stream.ReadSubBlockID();
285
286 // We only know the PCH subblock ID.
287 switch (BlockID) {
288 case llvm::bitc::BLOCKINFO_BLOCK_ID:
289 if (Stream.ReadBlockInfoBlock())
290 return Error("Malformed BlockInfoBlock");
291 break;
292 case pch::PCH_BLOCK_ID:
293 if (ReadPCHBlock())
294 return true;
295 break;
296 default:
297 if (Stream.SkipBlock())
298 return Error("Malformed block record");
299 break;
300 }
301 }
302
303 // Load the translation unit declaration
304 ReadDeclRecord(DeclOffsets[0], 0);
305
306 return false;
307}
308
309/// \brief Read and return the type at the given offset.
310///
311/// This routine actually reads the record corresponding to the type
312/// at the given offset in the bitstream. It is a helper routine for
313/// GetType, which deals with reading type IDs.
314QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
315 Stream.JumpToBit(Offset);
316 RecordData Record;
317 unsigned Code = Stream.ReadCode();
318 switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) {
319 case pch::TYPE_FIXED_WIDTH_INT: {
320 assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type");
321 return Context.getFixedWidthIntType(Record[0], Record[1]);
322 }
323
324 case pch::TYPE_COMPLEX: {
325 assert(Record.size() == 1 && "Incorrect encoding of complex type");
326 QualType ElemType = GetType(Record[0]);
327 return Context.getComplexType(ElemType);
328 }
329
330 case pch::TYPE_POINTER: {
331 assert(Record.size() == 1 && "Incorrect encoding of pointer type");
332 QualType PointeeType = GetType(Record[0]);
333 return Context.getPointerType(PointeeType);
334 }
335
336 case pch::TYPE_BLOCK_POINTER: {
337 assert(Record.size() == 1 && "Incorrect encoding of block pointer type");
338 QualType PointeeType = GetType(Record[0]);
339 return Context.getBlockPointerType(PointeeType);
340 }
341
342 case pch::TYPE_LVALUE_REFERENCE: {
343 assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type");
344 QualType PointeeType = GetType(Record[0]);
345 return Context.getLValueReferenceType(PointeeType);
346 }
347
348 case pch::TYPE_RVALUE_REFERENCE: {
349 assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type");
350 QualType PointeeType = GetType(Record[0]);
351 return Context.getRValueReferenceType(PointeeType);
352 }
353
354 case pch::TYPE_MEMBER_POINTER: {
355 assert(Record.size() == 1 && "Incorrect encoding of member pointer type");
356 QualType PointeeType = GetType(Record[0]);
357 QualType ClassType = GetType(Record[1]);
358 return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr());
359 }
360
361 // FIXME: Several other kinds of types to deserialize here!
362 default:
Douglas Gregorac8f2802009-04-10 17:25:41 +0000363 assert(false && "Unable to deserialize this type");
Douglas Gregorc34897d2009-04-09 22:27:44 +0000364 break;
365 }
366
367 // Suppress a GCC warning
368 return QualType();
369}
370
371/// \brief Note that we have loaded the declaration with the given
372/// Index.
373///
374/// This routine notes that this declaration has already been loaded,
375/// so that future GetDecl calls will return this declaration rather
376/// than trying to load a new declaration.
377inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) {
378 assert(!DeclAlreadyLoaded[Index] && "Decl loaded twice?");
379 DeclAlreadyLoaded[Index] = true;
380 DeclOffsets[Index] = reinterpret_cast<uint64_t>(D);
381}
382
383/// \brief Read the declaration at the given offset from the PCH file.
384Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
385 Decl *D = 0;
386 Stream.JumpToBit(Offset);
387 RecordData Record;
388 unsigned Code = Stream.ReadCode();
389 unsigned Idx = 0;
390 PCHDeclReader Reader(*this, Record, Idx);
391 switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) {
392 case pch::DECL_TRANSLATION_UNIT:
393 assert(Index == 0 && "Translation unit must be at index 0");
394 Reader.VisitTranslationUnitDecl(Context.getTranslationUnitDecl());
395 D = Context.getTranslationUnitDecl();
396 LoadedDecl(Index, D);
397 break;
398
399 case pch::DECL_TYPEDEF: {
400 TypedefDecl *Typedef = TypedefDecl::Create(Context, 0, SourceLocation(),
401 0, QualType());
402 LoadedDecl(Index, Typedef);
403 Reader.VisitTypedefDecl(Typedef);
404 D = Typedef;
405 break;
406 }
407
408 case pch::DECL_VAR: {
409 VarDecl *Var = VarDecl::Create(Context, 0, SourceLocation(), 0, QualType(),
410 VarDecl::None, SourceLocation());
411 LoadedDecl(Index, Var);
412 Reader.VisitVarDecl(Var);
413 D = Var;
414 break;
415 }
416
417 default:
418 assert(false && "Cannot de-serialize this kind of declaration");
419 break;
420 }
421
422 // If this declaration is also a declaration context, get the
423 // offsets for its tables of lexical and visible declarations.
424 if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
425 std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);
426 if (Offsets.first || Offsets.second) {
427 DC->setHasExternalLexicalStorage(Offsets.first != 0);
428 DC->setHasExternalVisibleStorage(Offsets.second != 0);
429 DeclContextOffsets[DC] = Offsets;
430 }
431 }
432 assert(Idx == Record.size());
433
434 return D;
435}
436
Douglas Gregorac8f2802009-04-10 17:25:41 +0000437QualType PCHReader::GetType(pch::TypeID ID) {
Douglas Gregorc34897d2009-04-09 22:27:44 +0000438 unsigned Quals = ID & 0x07;
439 unsigned Index = ID >> 3;
440
441 if (Index < pch::NUM_PREDEF_TYPE_IDS) {
442 QualType T;
443 switch ((pch::PredefinedTypeIDs)Index) {
444 case pch::PREDEF_TYPE_NULL_ID: return QualType();
445 case pch::PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break;
446 case pch::PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break;
447
448 case pch::PREDEF_TYPE_CHAR_U_ID:
449 case pch::PREDEF_TYPE_CHAR_S_ID:
450 // FIXME: Check that the signedness of CharTy is correct!
451 T = Context.CharTy;
452 break;
453
454 case pch::PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break;
455 case pch::PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break;
456 case pch::PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break;
457 case pch::PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break;
458 case pch::PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break;
459 case pch::PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break;
460 case pch::PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break;
461 case pch::PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break;
462 case pch::PREDEF_TYPE_INT_ID: T = Context.IntTy; break;
463 case pch::PREDEF_TYPE_LONG_ID: T = Context.LongTy; break;
464 case pch::PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break;
465 case pch::PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break;
466 case pch::PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break;
467 case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
468 case pch::PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
469 case pch::PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
470 }
471
472 assert(!T.isNull() && "Unknown predefined type");
473 return T.getQualifiedType(Quals);
474 }
475
476 Index -= pch::NUM_PREDEF_TYPE_IDS;
477 if (!TypeAlreadyLoaded[Index]) {
478 // Load the type from the PCH file.
479 TypeOffsets[Index] = reinterpret_cast<uint64_t>(
480 ReadTypeRecord(TypeOffsets[Index]).getTypePtr());
481 TypeAlreadyLoaded[Index] = true;
482 }
483
484 return QualType(reinterpret_cast<Type *>(TypeOffsets[Index]), Quals);
485}
486
Douglas Gregorac8f2802009-04-10 17:25:41 +0000487Decl *PCHReader::GetDecl(pch::DeclID ID) {
Douglas Gregorc34897d2009-04-09 22:27:44 +0000488 if (ID == 0)
489 return 0;
490
491 unsigned Index = ID - 1;
492 if (DeclAlreadyLoaded[Index])
493 return reinterpret_cast<Decl *>(DeclOffsets[Index]);
494
495 // Load the declaration from the PCH file.
496 return ReadDeclRecord(DeclOffsets[Index], Index);
497}
498
499bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
Douglas Gregorac8f2802009-04-10 17:25:41 +0000500 llvm::SmallVectorImpl<pch::DeclID> &Decls) {
Douglas Gregorc34897d2009-04-09 22:27:44 +0000501 assert(DC->hasExternalLexicalStorage() &&
502 "DeclContext has no lexical decls in storage");
503 uint64_t Offset = DeclContextOffsets[DC].first;
504 assert(Offset && "DeclContext has no lexical decls in storage");
505
506 // Load the record containing all of the declarations lexically in
507 // this context.
508 Stream.JumpToBit(Offset);
509 RecordData Record;
510 unsigned Code = Stream.ReadCode();
511 unsigned RecCode = Stream.ReadRecord(Code, Record);
512 assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block");
513
514 // Load all of the declaration IDs
515 Decls.clear();
516 Decls.insert(Decls.end(), Record.begin(), Record.end());
517 return false;
518}
519
520bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
521 llvm::SmallVectorImpl<VisibleDeclaration> & Decls) {
522 assert(DC->hasExternalVisibleStorage() &&
523 "DeclContext has no visible decls in storage");
524 uint64_t Offset = DeclContextOffsets[DC].second;
525 assert(Offset && "DeclContext has no visible decls in storage");
526
527 // Load the record containing all of the declarations visible in
528 // this context.
529 Stream.JumpToBit(Offset);
530 RecordData Record;
531 unsigned Code = Stream.ReadCode();
532 unsigned RecCode = Stream.ReadRecord(Code, Record);
533 assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block");
534 if (Record.size() == 0)
535 return false;
536
537 Decls.clear();
538
539 unsigned Idx = 0;
540 // llvm::SmallVector<uintptr_t, 16> DeclIDs;
541 while (Idx < Record.size()) {
542 Decls.push_back(VisibleDeclaration());
543 Decls.back().Name = ReadDeclarationName(Record, Idx);
544
545 // FIXME: Don't actually read anything here!
546 unsigned Size = Record[Idx++];
547 llvm::SmallVector<unsigned, 4> & LoadedDecls
548 = Decls.back().Declarations;
549 LoadedDecls.reserve(Size);
550 for (unsigned I = 0; I < Size; ++I)
551 LoadedDecls.push_back(Record[Idx++]);
552 }
553
554 return false;
555}
556
557void PCHReader::PrintStats() {
558 std::fprintf(stderr, "*** PCH Statistics:\n");
559
560 unsigned NumTypesLoaded = std::count(TypeAlreadyLoaded.begin(),
561 TypeAlreadyLoaded.end(),
562 true);
563 unsigned NumDeclsLoaded = std::count(DeclAlreadyLoaded.begin(),
564 DeclAlreadyLoaded.end(),
565 true);
566 std::fprintf(stderr, " %u/%u types read (%f%%)\n",
567 NumTypesLoaded, (unsigned)TypeAlreadyLoaded.size(),
568 ((float)NumTypesLoaded/(float)TypeAlreadyLoaded.size() * 100));
569 std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
570 NumDeclsLoaded, (unsigned)DeclAlreadyLoaded.size(),
571 ((float)NumDeclsLoaded/(float)DeclAlreadyLoaded.size() * 100));
572 std::fprintf(stderr, "\n");
573}
574
575const IdentifierInfo *PCHReader::GetIdentifierInfo(const RecordData &Record,
576 unsigned &Idx) {
577 // FIXME: we need unique IDs for identifiers.
578 std::string Str;
579 unsigned Length = Record[Idx++];
580 Str.resize(Length);
581 for (unsigned I = 0; I != Length; ++I)
582 Str[I] = Record[Idx++];
583 return &Context.Idents.get(Str);
584}
585
586DeclarationName
587PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
588 DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
589 switch (Kind) {
590 case DeclarationName::Identifier:
591 return DeclarationName(GetIdentifierInfo(Record, Idx));
592
593 case DeclarationName::ObjCZeroArgSelector:
594 case DeclarationName::ObjCOneArgSelector:
595 case DeclarationName::ObjCMultiArgSelector:
596 assert(false && "Unable to de-serialize Objective-C selectors");
597 break;
598
599 case DeclarationName::CXXConstructorName:
600 return Context.DeclarationNames.getCXXConstructorName(
601 GetType(Record[Idx++]));
602
603 case DeclarationName::CXXDestructorName:
604 return Context.DeclarationNames.getCXXDestructorName(
605 GetType(Record[Idx++]));
606
607 case DeclarationName::CXXConversionFunctionName:
608 return Context.DeclarationNames.getCXXConversionFunctionName(
609 GetType(Record[Idx++]));
610
611 case DeclarationName::CXXOperatorName:
612 return Context.DeclarationNames.getCXXOperatorName(
613 (OverloadedOperatorKind)Record[Idx++]);
614
615 case DeclarationName::CXXUsingDirective:
616 return DeclarationName::getUsingDirectiveName();
617 }
618
619 // Required to silence GCC warning
620 return DeclarationName();
621}