Add PCH read/write support for Objective-C Selectors.

Note: This support is non-lazy. Once we get "Cocoa.h" humming, we can optimize this.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69884 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 851eebc..0e2d06e 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1063,7 +1063,7 @@
 
 unsigned PCHStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
   VisitExpr(E);
-  // FIXME: Selectors.
+  E->setSelector(Reader.GetSelector(Record, Idx));
   E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
   E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
   return 0;
@@ -1586,8 +1586,69 @@
   }
 }
 
+bool PCHReader::ReadSelectorBlock() {
+  if (Stream.EnterSubBlock(pch::SELECTOR_BLOCK_ID))
+    return Error("Malformed selector block record");
+  
+  RecordData Record;
+  while (true) {
+    unsigned Code = Stream.ReadCode();
+    switch (Code) {
+    case llvm::bitc::END_BLOCK:
+      if (Stream.ReadBlockEnd())
+        return Error("Error at end of preprocessor block");
+      return false;
+    
+    case llvm::bitc::ENTER_SUBBLOCK:
+      // No known subblocks, always skip them.
+      Stream.ReadSubBlockID();
+      if (Stream.SkipBlock())
+        return Error("Malformed block record");
+      continue;
+    
+    case llvm::bitc::DEFINE_ABBREV:
+      Stream.ReadAbbrevRecord();
+      continue;
+    default: break;
+    }
+    
+    // Read a record.
+    Record.clear();
+    pch::PCHRecordTypes RecType =
+      (pch::PCHRecordTypes)Stream.ReadRecord(Code, Record);
+    switch (RecType) {
+    default:  // Default behavior: ignore unknown records.
+      break;
+    case pch::SELECTOR_TABLE:
+      unsigned Idx = 1; // Record[0] == pch::SELECTOR_TABLE.
+      unsigned NumSels = Record[Idx++];
+      
+      llvm::SmallVector<IdentifierInfo *, 8> KeyIdents;
+      for (unsigned SelIdx = 0; SelIdx < NumSels; SelIdx++) {
+        unsigned NumArgs = Record[Idx++];
+        KeyIdents.clear();
+        if (NumArgs <= 1) {
+          IdentifierInfo *II = DecodeIdentifierInfo(Record[Idx++]);
+          assert(II && "DecodeIdentifierInfo returned 0");
+          KeyIdents.push_back(II);
+        } else {
+          for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+            IdentifierInfo *II = DecodeIdentifierInfo(Record[Idx++]);
+            assert(II && "DecodeIdentifierInfo returned 0");
+            KeyIdents.push_back(II);
+          }
+        }
+        Selector Sel = PP.getSelectorTable().getSelector(NumArgs,&KeyIdents[0]);
+        SelectorData.push_back(Sel);
+      }
+    }
+  }
+  return false;
+}
+
 PCHReader::PCHReadResult 
-PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
+PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset,
+                        uint64_t &SelectorBlockOffset) {
   if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
     Error("Malformed block record");
     return Failure;
@@ -1630,6 +1691,20 @@
           return Failure;
         }
         break;
+
+      case pch::SELECTOR_BLOCK_ID:
+        // Skip the selector block for now, but remember where it is.  We
+        // want to read it in after the identifier table.
+        if (SelectorBlockOffset) {
+          Error("Multiple selector blocks found.");
+          return Failure;
+        }
+        SelectorBlockOffset = Stream.GetCurrentBitNo();
+        if (Stream.SkipBlock()) {
+          Error("Malformed block record");
+          return Failure;
+        }
+        break;
           
       case pch::SOURCE_MANAGER_BLOCK_ID:
         switch (ReadSourceManagerBlock()) {
@@ -1740,7 +1815,6 @@
       TotalLexicalDeclContexts = Record[2];
       TotalVisibleDeclContexts = Record[3];
       break;
-
     case pch::TENTATIVE_DEFINITIONS:
       if (!TentativeDefinitions.empty()) {
         Error("Duplicate TENTATIVE_DEFINITIONS record in PCH file");
@@ -1758,7 +1832,6 @@
       break;
     }
   }
-
   Error("Premature end of bitstream");
   return Failure;
 }
@@ -1791,6 +1864,8 @@
   // We expect a number of well-defined blocks, though we don't necessarily
   // need to understand them all.
   uint64_t PreprocessorBlockOffset = 0;
+  uint64_t SelectorBlockOffset = 0;
+  
   while (!Stream.AtEndOfStream()) {
     unsigned Code = Stream.ReadCode();
     
@@ -1810,7 +1885,7 @@
       }
       break;
     case pch::PCH_BLOCK_ID:
-      switch (ReadPCHBlock(PreprocessorBlockOffset)) {
+      switch (ReadPCHBlock(PreprocessorBlockOffset, SelectorBlockOffset)) {
       case Success:
         break;
 
@@ -1882,6 +1957,14 @@
       return Failure;
     }
   }
+  if (SelectorBlockOffset) {
+    SavedStreamPosition SavedPos(Stream);
+    Stream.JumpToBit(SelectorBlockOffset);
+    if (ReadSelectorBlock()) {
+      Error("Malformed preprocessor block");
+      return Failure;
+    }
+  }
 
   return Success;
 }
@@ -2633,6 +2716,22 @@
   return reinterpret_cast<IdentifierInfo *>(IdentifierData[ID - 1]);
 }
 
+Selector PCHReader::DecodeSelector(unsigned ID) {
+  if (ID == 0)
+    return Selector();
+  
+  if (SelectorData.empty()) {
+    Error("No selector table in PCH file");
+    return Selector();
+  }
+  
+  if (ID > SelectorData.size()) {
+    Error("Selector ID out of range");
+    return Selector();
+  }
+  return SelectorData[ID-1];
+}
+
 DeclarationName 
 PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
   DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];