Home | History | Annotate | Line # | Download | only in Frontend
      1 //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===//
      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 #include "TestModuleFileExtension.h"
      9 #include "clang/Frontend/FrontendDiagnostic.h"
     10 #include "clang/Serialization/ASTReader.h"
     11 #include "llvm/ADT/Hashing.h"
     12 #include "llvm/Bitstream/BitstreamWriter.h"
     13 #include "llvm/Support/raw_ostream.h"
     14 #include <cstdio>
     15 using namespace clang;
     16 using namespace clang::serialization;
     17 
     18 char TestModuleFileExtension::ID = 0;
     19 
     20 TestModuleFileExtension::Writer::~Writer() { }
     21 
     22 void TestModuleFileExtension::Writer::writeExtensionContents(
     23        Sema &SemaRef,
     24        llvm::BitstreamWriter &Stream) {
     25   using namespace llvm;
     26 
     27   // Write an abbreviation for this record.
     28   auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
     29   Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID));
     30   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters
     31   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));   // message
     32   auto Abbrev = Stream.EmitAbbrev(std::move(Abv));
     33 
     34   // Write a message into the extension block.
     35   SmallString<64> Message;
     36   {
     37     auto Ext = static_cast<TestModuleFileExtension *>(getExtension());
     38     raw_svector_ostream OS(Message);
     39     OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "."
     40        << Ext->MinorVersion;
     41   }
     42   uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()};
     43   Stream.EmitRecordWithBlob(Abbrev, Record, Message);
     44 }
     45 
     46 TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext,
     47                                         const llvm::BitstreamCursor &InStream)
     48   : ModuleFileExtensionReader(Ext), Stream(InStream)
     49 {
     50   // Read the extension block.
     51   SmallVector<uint64_t, 4> Record;
     52   while (true) {
     53     llvm::Expected<llvm::BitstreamEntry> MaybeEntry =
     54         Stream.advanceSkippingSubblocks();
     55     if (!MaybeEntry)
     56       (void)MaybeEntry.takeError();
     57     llvm::BitstreamEntry Entry = MaybeEntry.get();
     58 
     59     switch (Entry.Kind) {
     60     case llvm::BitstreamEntry::SubBlock:
     61     case llvm::BitstreamEntry::EndBlock:
     62     case llvm::BitstreamEntry::Error:
     63       return;
     64 
     65     case llvm::BitstreamEntry::Record:
     66       break;
     67     }
     68 
     69     Record.clear();
     70     StringRef Blob;
     71     Expected<unsigned> MaybeRecCode =
     72         Stream.readRecord(Entry.ID, Record, &Blob);
     73     if (!MaybeRecCode)
     74       fprintf(stderr, "Failed reading rec code: %s\n",
     75               toString(MaybeRecCode.takeError()).c_str());
     76     switch (MaybeRecCode.get()) {
     77     case FIRST_EXTENSION_RECORD_ID: {
     78       StringRef Message = Blob.substr(0, Record[0]);
     79       fprintf(stderr, "Read extension block message: %s\n",
     80               Message.str().c_str());
     81       break;
     82     }
     83     }
     84   }
     85 }
     86 
     87 TestModuleFileExtension::Reader::~Reader() { }
     88 
     89 TestModuleFileExtension::~TestModuleFileExtension() { }
     90 
     91 ModuleFileExtensionMetadata
     92 TestModuleFileExtension::getExtensionMetadata() const {
     93   return { BlockName, MajorVersion, MinorVersion, UserInfo };
     94 }
     95 
     96 llvm::hash_code TestModuleFileExtension::hashExtension(
     97                   llvm::hash_code Code) const {
     98   if (Hashed) {
     99     Code = llvm::hash_combine(Code, BlockName);
    100     Code = llvm::hash_combine(Code, MajorVersion);
    101     Code = llvm::hash_combine(Code, MinorVersion);
    102     Code = llvm::hash_combine(Code, UserInfo);
    103   }
    104 
    105   return Code;
    106 }
    107 
    108 std::unique_ptr<ModuleFileExtensionWriter>
    109 TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
    110   return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
    111 }
    112 
    113 std::unique_ptr<ModuleFileExtensionReader>
    114 TestModuleFileExtension::createExtensionReader(
    115   const ModuleFileExtensionMetadata &Metadata,
    116   ASTReader &Reader, serialization::ModuleFile &Mod,
    117   const llvm::BitstreamCursor &Stream)
    118 {
    119   assert(Metadata.BlockName == BlockName && "Wrong block name");
    120   if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
    121         std::make_pair(MajorVersion, MinorVersion)) {
    122     Reader.getDiags().Report(Mod.ImportLoc,
    123                              diag::err_test_module_file_extension_version)
    124       << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
    125       << MajorVersion << MinorVersion;
    126     return nullptr;
    127   }
    128 
    129   return std::unique_ptr<ModuleFileExtensionReader>(
    130                                                     new TestModuleFileExtension::Reader(this, Stream));
    131 }
    132 
    133 std::string TestModuleFileExtension::str() const {
    134   std::string Buffer;
    135   llvm::raw_string_ostream OS(Buffer);
    136   OS << BlockName << ":" << MajorVersion << ":" << MinorVersion << ":" << Hashed
    137      << ":" << UserInfo;
    138   return OS.str();
    139 }
    140