Implemented serialization for IdentifierInfo and IdentifierTable.
Updated serialization test code in the driver to test serialization of
these types.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43266 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Driver/SerializationTest.cpp b/Driver/SerializationTest.cpp
index 1901591..811dddb 100644
--- a/Driver/SerializationTest.cpp
+++ b/Driver/SerializationTest.cpp
@@ -19,226 +19,148 @@
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "llvm/System/Path.h"
-#include "llvm/Bitcode/BitstreamWriter.h"
-#include <fstream>
-#include <iostream>
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Bitcode/Serialization.h"
+#include <stdio.h>
+
+//===----------------------------------------------------------------------===//
+// Driver code.
+//===----------------------------------------------------------------------===//
 
 using namespace clang;
-using llvm::BitstreamWriter;
-using std::cerr;
-using std::cout;
-using std::endl;
-using std::flush;
-
-namespace llvm {  
-template<typename T> struct IntrospectionTrait {
-  struct Flags { 
-    enum { isPod = false, UniqueInstances = false, UniqueRefs = false };
-  };
-  
-  template<typename Introspector>
-  struct Ops {
-    static inline void Introspect(T& X, Introspector& I) {
-      assert (false && "Introspect not implemented.");
-    }
-  };
-};
-}
 
 namespace {
-class SerializationTest : public ASTConsumer {
-  IdentifierTable* IdTable;
-  unsigned MainFileID;
-public:
-  void Initialize(ASTContext& Context, unsigned mainFileID) {
-    IdTable = &Context.Idents;
-    MainFileID = mainFileID;
-    RunSerializationTest();
-  }
-  
-  void RunSerializationTest();
-  bool WriteAll(llvm::sys::Path& Filename);
-  
-  virtual void HandleTopLevelDecl(Decl *D) {}
-};
+  template<typename T>
+  struct Janitor {
+    T* Obj;
+    Janitor(T* obj) : Obj(obj) {}
+    ~Janitor() { delete Obj; }
+  };
+} // end anonymous namespace
 
-class Writer {
-  std::vector<unsigned char> Buffer;
-  BitstreamWriter Stream;
-  std::ostream& Out;
-public:
-  
-  enum { IdentifierTableBID = 0x8 };
-  
-  Writer(std::ostream& out) : Stream(Buffer), Out(out) {
-    Buffer.reserve(256*1024);
+namespace {
+  class SerializationTest : public ASTConsumer {
+    IdentifierTable* IdTable;
+    unsigned MainFileID;
+  public:
+    void Initialize(ASTContext& Context, unsigned mainFileID) {
+      IdTable = &Context.Idents;
+      MainFileID = mainFileID;
+    }
     
-    // Emit the file header.
-    Stream.Emit((unsigned)'B', 8);
-    Stream.Emit((unsigned)'C', 8);
-    Stream.Emit(0xC, 4);
-    Stream.Emit(0xF, 4);
-    Stream.Emit(0xE, 4);
-    Stream.Emit(0x0, 4);
-  }
-  
-  ~Writer() {
-    Out.write((char*)&Buffer.front(), Buffer.size());
-    Out.flush();
-  }
-  
-  template <typename T> inline void operator()(T& x) {
-    llvm::IntrospectionTrait<T>::template Ops<Writer>::Introspect(x,*this);
-  }
+    ~SerializationTest() {
+      RunSerializationTest();
+    }
     
-  template <typename T> inline void operator()(T& x, unsigned bits) {
-    llvm::IntrospectionTrait<T>::template Ops<Writer>::Introspect(x,bits,*this);
-  }
-  
-  template <typename T> inline void operator()(const T& x) {
-    operator()(const_cast<T&>(x));
-  }
-  
-  template <typename T> inline void operator()(const T& x, unsigned bits) {
-    operator()(const_cast<T&>(x),bits);
-  }  
-  
-  inline void operator()(bool X) { Stream.Emit(X,1); }
-  inline void operator()(unsigned X) { Stream.Emit(X,32); }
-  inline void operator()(unsigned X, unsigned bits, bool VBR=false) {
-    if (VBR) Stream.Emit(X,bits);
-    else Stream.Emit(X,bits);
-  }
-  
-  inline BitstreamWriter& getStream() {
-    return Stream;
-  }
-  
-  template <typename T> inline void EnterSubblock(unsigned CodeLen) {
-    Stream.EnterSubblock(8,CodeLen);
-  }
-  
-  inline void ExitBlock() { Stream.ExitBlock(); }
-  
-};  
-  
-} // end anonymous namespace  
-
-//===----------------------------------------------------------------------===//
-// External Interface.
-//===----------------------------------------------------------------------===//
+    void RunSerializationTest();
+    bool WriteTable(llvm::sys::Path& Filename, IdentifierTable* T);
+    IdentifierTable* ReadTable(llvm::sys::Path& Filename);
+    
+    virtual void HandleTopLevelDecl(Decl *D) {}
+  };
+} // end anonymous namespace
 
 ASTConsumer* clang::CreateSerializationTest() {
   return new SerializationTest();
 }
-  
-//===----------------------------------------------------------------------===//
-// Serialization "Driver" code.
-//===----------------------------------------------------------------------===//
 
 void SerializationTest::RunSerializationTest() { 
   std::string ErrMsg;
   llvm::sys::Path Filename = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
-
+  
   if (Filename.isEmpty()) {
-    cerr << "Error: " << ErrMsg << "\n";
+    llvm::cerr << "Error: " << ErrMsg << "\n";
     return;
   }
   
-  Filename.appendComponent("test.cfe_bc");
+  Filename.appendComponent("test.ast");
   
   if (Filename.makeUnique(true,&ErrMsg)) {
-    cerr << "Error: " << ErrMsg << "\n";
+    llvm::cerr << "Error: " << ErrMsg << "\n";
     return;
   }
   
-  if (!WriteAll(Filename))
-    return;
+  llvm::cerr << "Writing out Identifier table\n";
+  WriteTable(Filename,IdTable);
+  llvm::cerr << "Reading in Identifier Table\n";
+  IdentifierTable* T = ReadTable(Filename);
+  Janitor<IdentifierTable> roger(T);
   
-  cout << "Wrote file: " << Filename.c_str() << "\n";
+  Filename.appendSuffix("2");
+  llvm::cerr << "Writing out Identifier table (2)\n";
+  WriteTable(Filename,T);
+  llvm::cerr << "Reading in Identifier Table (2)\n";
+  Janitor<IdentifierTable> wilco(ReadTable(Filename));
 }
 
-bool SerializationTest::WriteAll(llvm::sys::Path& Filename) {  
-  std::ofstream Out(Filename.c_str());
+bool SerializationTest::WriteTable(llvm::sys::Path& Filename,
+                                   IdentifierTable* T) {
+  if (!T)
+    return false;
   
-  if (!Out) {
-    cerr << "Error: Cannot open " << Filename.c_str() << "\n";
+  std::vector<unsigned char> Buffer;
+  Buffer.reserve(256*1024);
+  
+  llvm::BitstreamWriter Stream(Buffer);
+  
+  Stream.Emit((unsigned)'B', 8);
+  Stream.Emit((unsigned)'C', 8);
+  Stream.Emit(0xC, 4);
+  Stream.Emit(0xF, 4);
+  Stream.Emit(0xE, 4);
+  Stream.Emit(0x0, 4);
+
+  llvm::Serializer S(Stream);
+  S.Emit(*T);
+  S.Flush();
+  
+  if (FILE *fp = fopen(Filename.c_str(),"wb")) {
+    fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
+    fclose(fp);
+  }
+  else { 
+    llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
     return false;
   }
-    
-  Writer W(Out);
-  W(*IdTable);
-
-  W.getStream().FlushToWord();
+  
+  llvm::cerr << "Wrote file: " << Filename.c_str() << "\n";
   return true;
 }
 
-//===----------------------------------------------------------------------===//
-// Serialization Methods.
-//===----------------------------------------------------------------------===//
 
-namespace llvm {
-
-struct IntrospectionPrimitivesFlags {
-  enum { isPod = true, UniqueInstances = false, UniqueRefs = false };
-};
+IdentifierTable* SerializationTest::ReadTable(llvm::sys::Path& Filename) {
+  llvm::MemoryBuffer* Buffer = 
+    llvm::MemoryBuffer::getFile(Filename.c_str(), strlen(Filename.c_str()));
   
-
-template<> struct
-IntrospectionTrait<bool>::Flags : public IntrospectionPrimitivesFlags {};
-  
-template<> struct
-IntrospectionTrait<unsigned>::Flags : public IntrospectionPrimitivesFlags {};
-
-template<> struct
-IntrospectionTrait<short>::Flags : public IntrospectionPrimitivesFlags {};
-
-
-
-template<> 
-struct IntrospectionTrait<clang::IdentifierInfo> {
-
-  struct Flags { 
-    enum { isPod = false,  // Cannot copy via memcpy.  Must use copy-ctor.    
-           hasUniqueInstances = true, // Two pointers with different
-                                      // addreses point to objects
-                                      // that are not equal to each other.    
-           hasUniqueReferences = true // Two (non-temporary) pointers                                    
-                                      // will point to distinct instances.
-    };
-  };
-
-  template<typename Introspector>
-  struct Ops {
-    static void Introspect(clang::IdentifierInfo& X, Introspector& I) {
-  //    I(X.getTokenID());
-      I(X.getBuiltinID(),9); // FIXME: do 9 bit specialization.
-  //    I(X.getObjCKeywordID());
-      I(X.hasMacroDefinition());
-      I(X.isExtensionToken());
-      I(X.isPoisoned());
-      I(X.isOtherTargetMacro());
-      I(X.isCPlusPlusOperatorKeyword());
-      I(X.isNonPortableBuiltin());
-    }
-  };
-};
-  
-template<> template<>
-struct IntrospectionTrait<clang::IdentifierTable>::Ops<Writer> {
-  static void Introspect(clang::IdentifierTable& X, Writer& W) {
-    W.EnterSubblock<clang::IdentifierTable>(1);
-/*        
-    for (clang::IdentifierTable::iterator I = X.begin(), E = X.end();
-         I != E; ++I)
-      W(I->getValue());
-   */ 
-    W.ExitBlock();
+  if(!Buffer) {
+    llvm::cerr << "Error reading file\n";
+    return NULL;
   }
-};
-
   
-
+  Janitor<llvm::MemoryBuffer> AutoReleaseBuffer(Buffer);
   
-} // end namespace llvm
+  if (Buffer->getBufferSize() & 0x3) {
+    llvm::cerr << "AST file should be a multiple of 4 bytes in length\n";
+    return NULL;
+  }
+  
+  unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
+  llvm::BitstreamReader Stream(BufPtr,BufPtr+Buffer->getBufferSize());
+  
+  // Sniff for the signature.
+  if (Stream.Read(8) != 'B' ||
+      Stream.Read(8) != 'C' ||
+      Stream.Read(4) != 0xC ||
+      Stream.Read(4) != 0xF ||
+      Stream.Read(4) != 0xE ||
+      Stream.Read(4) != 0x0) {
+    llvm::cerr << "Invalid AST-bitcode signature\n";
+    return NULL;
+  }
+  
+  llvm::Deserializer D(Stream);
 
+  llvm::cerr << "Materializing identifier table.\n";
+  return D.Materialize<IdentifierTable>();
+}