[clang-tools-extra] r333932 - [clang-doc] Implement reducer portion of the frontend framework

Julie Hockett via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 4 10:22:20 PDT 2018


Author: juliehockett
Date: Mon Jun  4 10:22:20 2018
New Revision: 333932

URL: http://llvm.org/viewvc/llvm-project?rev=333932&view=rev
Log:
[clang-doc] Implement reducer portion of the frontend framework

Implements a simple, in-memory reducer for the mapped output of the
initial tool. This creates a collection object for storing the
deduplicated infos on each declaration, and populates that from the
mapper output. The collection object is serialized to LLVM
bitstream. On reading each serialized output, it checks to see if a
merge is necessary and if so, merges the new info with the existing
info (prefering the existing one if conflicts exist).

For a more detailed overview of the tool, see the design document
on the mailing list:
http://lists.llvm.org/pipermail/cfe-dev/2017-December/056203.html

Differential Revision: https://reviews.llvm.org/D43341

Added:
    clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp
    clang-tools-extra/trunk/clang-doc/BitcodeReader.h
    clang-tools-extra/trunk/clang-doc/Representation.cpp
    clang-tools-extra/trunk/test/clang-doc/bc-comment.cpp
    clang-tools-extra/trunk/test/clang-doc/bc-namespace.cpp
    clang-tools-extra/trunk/test/clang-doc/bc-record.cpp
Modified:
    clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
    clang-tools-extra/trunk/clang-doc/BitcodeWriter.h
    clang-tools-extra/trunk/clang-doc/CMakeLists.txt
    clang-tools-extra/trunk/clang-doc/Representation.h
    clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp

Added: clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp?rev=333932&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp (added)
+++ clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp Mon Jun  4 10:22:20 2018
@@ -0,0 +1,622 @@
+//===--  BitcodeReader.cpp - ClangDoc Bitcode Reader ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BitcodeReader.h"
+#include "llvm/ADT/IndexedMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace doc {
+
+using Record = llvm::SmallVector<uint64_t, 1024>;
+
+bool decodeRecord(Record R, llvm::SmallVectorImpl<char> &Field,
+                  llvm::StringRef Blob) {
+  Field.assign(Blob.begin(), Blob.end());
+  return true;
+}
+
+bool decodeRecord(Record R, SymbolID &Field, llvm::StringRef Blob) {
+  if (R[0] != BitCodeConstants::USRHashSize)
+    return false;
+
+  // First position in the record is the length of the following array, so we
+  // copy the following elements to the field.
+  for (int I = 0, E = R[0]; I < E; ++I)
+    Field[I] = R[I + 1];
+  return true;
+}
+
+bool decodeRecord(Record R, bool &Field, llvm::StringRef Blob) {
+  Field = R[0] != 0;
+  return true;
+}
+
+bool decodeRecord(Record R, int &Field, llvm::StringRef Blob) {
+  if (R[0] > INT_MAX)
+    return false;
+  Field = (int)R[0];
+  return true;
+}
+
+bool decodeRecord(Record R, AccessSpecifier &Field, llvm::StringRef Blob) {
+  switch (R[0]) {
+  case AS_public:
+  case AS_private:
+  case AS_protected:
+  case AS_none:
+    Field = (AccessSpecifier)R[0];
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool decodeRecord(Record R, TagTypeKind &Field, llvm::StringRef Blob) {
+  switch (R[0]) {
+  case TTK_Struct:
+  case TTK_Interface:
+  case TTK_Union:
+  case TTK_Class:
+  case TTK_Enum:
+    Field = (TagTypeKind)R[0];
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool decodeRecord(Record R, llvm::Optional<Location> &Field,
+                  llvm::StringRef Blob) {
+  if (R[0] > INT_MAX)
+    return false;
+  Field.emplace((int)R[0], Blob);
+  return true;
+}
+
+bool decodeRecord(Record R, InfoType &Field, llvm::StringRef Blob) {
+  switch (auto IT = static_cast<InfoType>(R[0])) {
+  case InfoType::IT_namespace:
+  case InfoType::IT_record:
+  case InfoType::IT_function:
+  case InfoType::IT_default:
+  case InfoType::IT_enum:
+    Field = IT;
+    return true;
+  }
+  return false;
+}
+
+bool decodeRecord(Record R, FieldId &Field, llvm::StringRef Blob) {
+  switch (auto F = static_cast<FieldId>(R[0])) {
+  case FieldId::F_namespace:
+  case FieldId::F_parent:
+  case FieldId::F_vparent:
+  case FieldId::F_type:
+  case FieldId::F_default:
+    Field = F;
+    return true;
+  }
+  return false;
+}
+
+bool decodeRecord(Record R, llvm::SmallVectorImpl<llvm::SmallString<16>> &Field,
+                  llvm::StringRef Blob) {
+  Field.push_back(Blob);
+  return true;
+}
+
+bool decodeRecord(Record R, llvm::SmallVectorImpl<Location> &Field,
+                  llvm::StringRef Blob) {
+  if (R[0] > INT_MAX)
+    return false;
+  Field.emplace_back((int)R[0], Blob);
+  return true;
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
+                 const unsigned VersionNo) {
+  if (ID == VERSION && R[0] == VersionNo)
+    return true;
+  return false;
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
+                 NamespaceInfo *I) {
+  switch (ID) {
+  case NAMESPACE_USR:
+    return decodeRecord(R, I->USR, Blob);
+  case NAMESPACE_NAME:
+    return decodeRecord(R, I->Name, Blob);
+  default:
+    return false;
+  }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, RecordInfo *I) {
+  switch (ID) {
+  case RECORD_USR:
+    return decodeRecord(R, I->USR, Blob);
+  case RECORD_NAME:
+    return decodeRecord(R, I->Name, Blob);
+  case RECORD_DEFLOCATION:
+    return decodeRecord(R, I->DefLoc, Blob);
+  case RECORD_LOCATION:
+    return decodeRecord(R, I->Loc, Blob);
+  case RECORD_TAG_TYPE:
+    return decodeRecord(R, I->TagType, Blob);
+  default:
+    return false;
+  }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, EnumInfo *I) {
+  switch (ID) {
+  case ENUM_USR:
+    return decodeRecord(R, I->USR, Blob);
+  case ENUM_NAME:
+    return decodeRecord(R, I->Name, Blob);
+  case ENUM_DEFLOCATION:
+    return decodeRecord(R, I->DefLoc, Blob);
+  case ENUM_LOCATION:
+    return decodeRecord(R, I->Loc, Blob);
+  case ENUM_MEMBER:
+    return decodeRecord(R, I->Members, Blob);
+  case ENUM_SCOPED:
+    return decodeRecord(R, I->Scoped, Blob);
+  default:
+    return false;
+  }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, FunctionInfo *I) {
+  switch (ID) {
+  case FUNCTION_USR:
+    return decodeRecord(R, I->USR, Blob);
+  case FUNCTION_NAME:
+    return decodeRecord(R, I->Name, Blob);
+  case FUNCTION_DEFLOCATION:
+    return decodeRecord(R, I->DefLoc, Blob);
+  case FUNCTION_LOCATION:
+    return decodeRecord(R, I->Loc, Blob);
+  case FUNCTION_ACCESS:
+    return decodeRecord(R, I->Access, Blob);
+  case FUNCTION_IS_METHOD:
+    return decodeRecord(R, I->IsMethod, Blob);
+  default:
+    return false;
+  }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, TypeInfo *I) {
+  return true;
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
+                 FieldTypeInfo *I) {
+  switch (ID) {
+  case FIELD_TYPE_NAME:
+    return decodeRecord(R, I->Name, Blob);
+  default:
+    return false;
+  }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
+                 MemberTypeInfo *I) {
+  switch (ID) {
+  case MEMBER_TYPE_NAME:
+    return decodeRecord(R, I->Name, Blob);
+  case MEMBER_TYPE_ACCESS:
+    return decodeRecord(R, I->Access, Blob);
+  default:
+    return false;
+  }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, CommentInfo *I) {
+  switch (ID) {
+  case COMMENT_KIND:
+    return decodeRecord(R, I->Kind, Blob);
+  case COMMENT_TEXT:
+    return decodeRecord(R, I->Text, Blob);
+  case COMMENT_NAME:
+    return decodeRecord(R, I->Name, Blob);
+  case COMMENT_DIRECTION:
+    return decodeRecord(R, I->Direction, Blob);
+  case COMMENT_PARAMNAME:
+    return decodeRecord(R, I->ParamName, Blob);
+  case COMMENT_CLOSENAME:
+    return decodeRecord(R, I->CloseName, Blob);
+  case COMMENT_ATTRKEY:
+    return decodeRecord(R, I->AttrKeys, Blob);
+  case COMMENT_ATTRVAL:
+    return decodeRecord(R, I->AttrValues, Blob);
+  case COMMENT_ARG:
+    return decodeRecord(R, I->Args, Blob);
+  case COMMENT_SELFCLOSING:
+    return decodeRecord(R, I->SelfClosing, Blob);
+  case COMMENT_EXPLICIT:
+    return decodeRecord(R, I->Explicit, Blob);
+  default:
+    return false;
+  }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, Reference *I,
+                 FieldId &F) {
+  switch (ID) {
+  case REFERENCE_USR:
+    return decodeRecord(R, I->USR, Blob);
+  case REFERENCE_NAME:
+    return decodeRecord(R, I->Name, Blob);
+  case REFERENCE_TYPE:
+    return decodeRecord(R, I->RefType, Blob);
+  case REFERENCE_FIELD:
+    return decodeRecord(R, F, Blob);
+  default:
+    return false;
+  }
+}
+
+template <typename T> CommentInfo *getCommentInfo(T I) {
+  llvm::errs() << "Cannot have comment subblock.\n";
+  exit(1);
+}
+
+template <> CommentInfo *getCommentInfo(FunctionInfo *I) {
+  I->Description.emplace_back();
+  return &I->Description.back();
+}
+
+template <> CommentInfo *getCommentInfo(NamespaceInfo *I) {
+  I->Description.emplace_back();
+  return &I->Description.back();
+}
+
+template <> CommentInfo *getCommentInfo(RecordInfo *I) {
+  I->Description.emplace_back();
+  return &I->Description.back();
+}
+
+template <> CommentInfo *getCommentInfo(EnumInfo *I) {
+  I->Description.emplace_back();
+  return &I->Description.back();
+}
+
+template <> CommentInfo *getCommentInfo(CommentInfo *I) {
+  I->Children.emplace_back(llvm::make_unique<CommentInfo>());
+  return I->Children.back().get();
+}
+
+template <> CommentInfo *getCommentInfo(std::unique_ptr<CommentInfo> &I) {
+  return getCommentInfo(I.get());
+}
+
+template <typename T, typename TTypeInfo>
+void addTypeInfo(T I, TTypeInfo &&TI) {
+  llvm::errs() << "Invalid type for info.\n";
+  exit(1);
+}
+
+template <> void addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) {
+  I->Members.emplace_back(std::move(T));
+}
+
+template <> void addTypeInfo(FunctionInfo *I, TypeInfo &&T) {
+  I->ReturnType = std::move(T);
+}
+
+template <> void addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) {
+  I->Params.emplace_back(std::move(T));
+}
+
+template <typename T> void addReference(T I, Reference &&R, FieldId F) {
+  llvm::errs() << "Invalid field type for info.\n";
+  exit(1);
+}
+
+template <> void addReference(TypeInfo *I, Reference &&R, FieldId F) {
+  switch (F) {
+  case FieldId::F_type:
+    I->Type = std::move(R);
+    break;
+  default:
+    llvm::errs() << "Invalid field type for info.\n";
+    exit(1);
+  }
+}
+
+template <> void addReference(FieldTypeInfo *I, Reference &&R, FieldId F) {
+  switch (F) {
+  case FieldId::F_type:
+    I->Type = std::move(R);
+    break;
+  default:
+    llvm::errs() << "Invalid field type for info.\n";
+    exit(1);
+  }
+}
+
+template <> void addReference(MemberTypeInfo *I, Reference &&R, FieldId F) {
+  switch (F) {
+  case FieldId::F_type:
+    I->Type = std::move(R);
+    break;
+  default:
+    llvm::errs() << "Invalid field type for info.\n";
+    exit(1);
+  }
+}
+
+template <> void addReference(EnumInfo *I, Reference &&R, FieldId F) {
+  switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    break;
+  default:
+    llvm::errs() << "Invalid field type for info.\n";
+    exit(1);
+  }
+}
+
+template <> void addReference(NamespaceInfo *I, Reference &&R, FieldId F) {
+  switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    break;
+  default:
+    llvm::errs() << "Invalid field type for info.\n";
+    exit(1);
+  }
+}
+
+template <> void addReference(FunctionInfo *I, Reference &&R, FieldId F) {
+  switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    break;
+  case FieldId::F_parent:
+    I->Parent = std::move(R);
+    break;
+  default:
+    llvm::errs() << "Invalid field type for info.\n";
+    exit(1);
+  }
+}
+
+template <> void addReference(RecordInfo *I, Reference &&R, FieldId F) {
+  switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    break;
+  case FieldId::F_parent:
+    I->Parents.emplace_back(std::move(R));
+    break;
+  case FieldId::F_vparent:
+    I->VirtualParents.emplace_back(std::move(R));
+    break;
+  default:
+    llvm::errs() << "Invalid field type for info.\n";
+    exit(1);
+  }
+}
+
+// Read records from bitcode into a given info.
+template <typename T> bool ClangDocBitcodeReader::readRecord(unsigned ID, T I) {
+  Record R;
+  llvm::StringRef Blob;
+  unsigned RecID = Stream.readRecord(ID, R, &Blob);
+  return parseRecord(R, RecID, Blob, I);
+}
+
+template <> bool ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) {
+  Record R;
+  llvm::StringRef Blob;
+  unsigned RecID = Stream.readRecord(ID, R, &Blob);
+  return parseRecord(R, RecID, Blob, I, CurrentReferenceField);
+}
+
+// Read a block of records into a single info.
+template <typename T> bool ClangDocBitcodeReader::readBlock(unsigned ID, T I) {
+  if (Stream.EnterSubBlock(ID))
+    return false;
+
+  while (true) {
+    unsigned BlockOrCode = 0;
+    Cursor Res = skipUntilRecordOrBlock(BlockOrCode);
+
+    switch (Res) {
+    case Cursor::BadBlock:
+      return false;
+    case Cursor::BlockEnd:
+      return true;
+    case Cursor::BlockBegin:
+      if (readSubBlock(BlockOrCode, I))
+        continue;
+      if (!Stream.SkipBlock())
+        return false;
+      continue;
+    case Cursor::Record:
+      break;
+    }
+    if (!readRecord(BlockOrCode, I))
+      return false;
+  }
+}
+
+template <typename T>
+bool ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
+  switch (ID) {
+  // Blocks can only have Comment, Reference, or TypeInfo subblocks
+  case BI_COMMENT_BLOCK_ID:
+    if (readBlock(ID, getCommentInfo(I)))
+      return true;
+    return false;
+  case BI_TYPE_BLOCK_ID: {
+    TypeInfo TI;
+    if (readBlock(ID, &TI)) {
+      addTypeInfo(I, std::move(TI));
+      return true;
+    }
+    return false;
+  }
+  case BI_FIELD_TYPE_BLOCK_ID: {
+    FieldTypeInfo TI;
+    if (readBlock(ID, &TI)) {
+      addTypeInfo(I, std::move(TI));
+      return true;
+    }
+    return false;
+  }
+  case BI_MEMBER_TYPE_BLOCK_ID: {
+    MemberTypeInfo TI;
+    if (readBlock(ID, &TI)) {
+      addTypeInfo(I, std::move(TI));
+      return true;
+    }
+    return false;
+  }
+  case BI_REFERENCE_BLOCK_ID: {
+    Reference R;
+    if (readBlock(ID, &R)) {
+      addReference(I, std::move(R), CurrentReferenceField);
+      return true;
+    }
+    return false;
+  }
+  default:
+    llvm::errs() << "Invalid subblock type.\n";
+    return false;
+  }
+}
+
+ClangDocBitcodeReader::Cursor
+ClangDocBitcodeReader::skipUntilRecordOrBlock(unsigned &BlockOrRecordID) {
+  BlockOrRecordID = 0;
+
+  while (!Stream.AtEndOfStream()) {
+    unsigned Code = Stream.ReadCode();
+
+    switch ((llvm::bitc::FixedAbbrevIDs)Code) {
+    case llvm::bitc::ENTER_SUBBLOCK:
+      BlockOrRecordID = Stream.ReadSubBlockID();
+      return Cursor::BlockBegin;
+    case llvm::bitc::END_BLOCK:
+      if (Stream.ReadBlockEnd())
+        return Cursor::BadBlock;
+      return Cursor::BlockEnd;
+    case llvm::bitc::DEFINE_ABBREV:
+      Stream.ReadAbbrevRecord();
+      continue;
+    case llvm::bitc::UNABBREV_RECORD:
+      return Cursor::BadBlock;
+    default:
+      BlockOrRecordID = Code;
+      return Cursor::Record;
+    }
+  }
+  llvm_unreachable("Premature stream end.");
+}
+
+bool ClangDocBitcodeReader::validateStream() {
+  if (Stream.AtEndOfStream())
+    return false;
+
+  // Sniff for the signature.
+  if (Stream.Read(8) != BitCodeConstants::Signature[0] ||
+      Stream.Read(8) != BitCodeConstants::Signature[1] ||
+      Stream.Read(8) != BitCodeConstants::Signature[2] ||
+      Stream.Read(8) != BitCodeConstants::Signature[3])
+    return false;
+  return true;
+}
+
+bool ClangDocBitcodeReader::readBlockInfoBlock() {
+  BlockInfo = Stream.ReadBlockInfoBlock();
+  if (!BlockInfo)
+    return false;
+  Stream.setBlockInfo(&*BlockInfo);
+  return true;
+}
+
+template <typename T>
+std::unique_ptr<Info> ClangDocBitcodeReader::createInfo(unsigned ID) {
+  std::unique_ptr<Info> I = llvm::make_unique<T>();
+  if (readBlock(ID, static_cast<T *>(I.get())))
+    return I;
+  llvm::errs() << "Error reading from block.\n";
+  return nullptr;
+}
+
+std::unique_ptr<Info> ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
+  switch (ID) {
+  case BI_NAMESPACE_BLOCK_ID:
+    return createInfo<NamespaceInfo>(ID);
+  case BI_RECORD_BLOCK_ID:
+    return createInfo<RecordInfo>(ID);
+  case BI_ENUM_BLOCK_ID:
+    return createInfo<EnumInfo>(ID);
+  case BI_FUNCTION_BLOCK_ID:
+    return createInfo<FunctionInfo>(ID);
+  default:
+    llvm::errs() << "Error reading from block.\n";
+    return nullptr;
+  }
+}
+
+// Entry point
+std::vector<std::unique_ptr<Info>> ClangDocBitcodeReader::readBitcode() {
+  std::vector<std::unique_ptr<Info>> Infos;
+  if (!validateStream())
+    return Infos;
+
+  // Read the top level blocks.
+  while (!Stream.AtEndOfStream()) {
+    unsigned Code = Stream.ReadCode();
+    if (Code != llvm::bitc::ENTER_SUBBLOCK)
+      return Infos;
+
+    unsigned ID = Stream.ReadSubBlockID();
+    switch (ID) {
+    // NamedType and Comment blocks should not appear at the top level
+    case BI_TYPE_BLOCK_ID:
+    case BI_FIELD_TYPE_BLOCK_ID:
+    case BI_MEMBER_TYPE_BLOCK_ID:
+    case BI_COMMENT_BLOCK_ID:
+    case BI_REFERENCE_BLOCK_ID:
+      llvm::errs() << "Invalid top level block.\n";
+      return Infos;
+    case BI_NAMESPACE_BLOCK_ID:
+    case BI_RECORD_BLOCK_ID:
+    case BI_ENUM_BLOCK_ID:
+    case BI_FUNCTION_BLOCK_ID:
+      if (std::unique_ptr<Info> I = readBlockToInfo(ID)) {
+        Infos.emplace_back(std::move(I));
+      }
+      return Infos;
+    case BI_VERSION_BLOCK_ID:
+      if (readBlock(ID, VersionNumber))
+        continue;
+      return Infos;
+    case llvm::bitc::BLOCKINFO_BLOCK_ID:
+      if (readBlockInfoBlock())
+        continue;
+      return Infos;
+    default:
+      if (!Stream.SkipBlock())
+        continue;
+    }
+  }
+  return Infos;
+}
+
+} // namespace doc
+} // namespace clang

Added: clang-tools-extra/trunk/clang-doc/BitcodeReader.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeReader.h?rev=333932&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeReader.h (added)
+++ clang-tools-extra/trunk/clang-doc/BitcodeReader.h Mon Jun  4 10:22:20 2018
@@ -0,0 +1,73 @@
+//===--  BitcodeReader.h - ClangDoc Bitcode Reader --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a reader for parsing the clang-doc internal
+// representation from LLVM bitcode. The reader takes in a stream of bits and
+// generates the set of infos that it represents.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEREADER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEREADER_H
+
+#include "BitcodeWriter.h"
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+
+namespace clang {
+namespace doc {
+
+// Class to read bitstream into an InfoSet collection
+class ClangDocBitcodeReader {
+public:
+  ClangDocBitcodeReader(llvm::BitstreamCursor &Stream) : Stream(Stream) {}
+
+  // Main entry point, calls readBlock to read each block in the given stream.
+  std::vector<std::unique_ptr<Info>> readBitcode();
+
+private:
+  enum class Cursor { BadBlock = 1, Record, BlockEnd, BlockBegin };
+
+  // Top level parsing
+  bool validateStream();
+  bool readVersion();
+  bool readBlockInfoBlock();
+
+  // Read a block of records into a single Info struct, calls readRecord on each
+  // record found.
+  template <typename T> bool readBlock(unsigned ID, T I);
+
+  // Step through a block of records to find the next data field.
+  template <typename T> bool readSubBlock(unsigned ID, T I);
+
+  // Read record data into the given Info data field, calling the appropriate
+  // parseRecord functions to parse and store the data.
+  template <typename T> bool readRecord(unsigned ID, T I);
+
+  // Allocate the relevant type of info and add read data to the object.
+  template <typename T> std::unique_ptr<Info> createInfo(unsigned ID);
+
+  // Helper function to step through blocks to find and dispatch the next record
+  // or block to be read.
+  Cursor skipUntilRecordOrBlock(unsigned &BlockOrRecordID);
+
+  // Helper function to set up the approriate type of Info.
+  std::unique_ptr<Info> readBlockToInfo(unsigned ID);
+
+  llvm::BitstreamCursor &Stream;
+  Optional<llvm::BitstreamBlockInfo> BlockInfo;
+  FieldId CurrentReferenceField;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEREADER_H

Modified: clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp?rev=333932&r1=333931&r2=333932&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp Mon Jun  4 10:22:20 2018
@@ -214,6 +214,8 @@ static const std::vector<std::pair<Block
 
 // AbbreviationMap
 
+constexpr char BitCodeConstants::Signature[];
+
 void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,
                                                  unsigned AbbrevID) {
   assert(RecordIdNameMap[RID] && "Unknown RecordId.");
@@ -232,7 +234,7 @@ unsigned ClangDocBitcodeWriter::Abbrevia
 /// \brief Emits the magic number header to check that its the right format,
 /// in this case, 'DOCS'.
 void ClangDocBitcodeWriter::emitHeader() {
-  for (char C : llvm::StringRef("DOCS"))
+  for (char C : BitCodeConstants::Signature)
     Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize);
 }
 
@@ -424,22 +426,24 @@ void ClangDocBitcodeWriter::emitBlock(co
     emitBlock(*C);
 }
 
-#define EMITINFO(X)                                                            \
-  emitRecord(I.USR, X##_USR);                                                  \
-  emitRecord(I.Name, X##_NAME);                                                \
-  for (const auto &N : I.Namespace)                                            \
-    emitBlock(N, FieldId::F_namespace);                                        \
-  for (const auto &CI : I.Description)                                         \
-    emitBlock(CI);
-
 void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
   StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
-  EMITINFO(NAMESPACE)
+  emitRecord(I.USR, NAMESPACE_USR);
+  emitRecord(I.Name, NAMESPACE_NAME);
+  for (const auto &N : I.Namespace)
+    emitBlock(N, FieldId::F_namespace);
+  for (const auto &CI : I.Description)
+    emitBlock(CI);
 }
 
 void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
   StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
-  EMITINFO(ENUM)
+  emitRecord(I.USR, ENUM_USR);
+  emitRecord(I.Name, ENUM_NAME);
+  for (const auto &N : I.Namespace)
+    emitBlock(N, FieldId::F_namespace);
+  for (const auto &CI : I.Description)
+    emitBlock(CI);
   if (I.DefLoc)
     emitRecord(I.DefLoc.getValue(), ENUM_DEFLOCATION);
   for (const auto &L : I.Loc)
@@ -451,7 +455,12 @@ void ClangDocBitcodeWriter::emitBlock(co
 
 void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
   StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
-  EMITINFO(RECORD)
+  emitRecord(I.USR, RECORD_USR);
+  emitRecord(I.Name, RECORD_NAME);
+  for (const auto &N : I.Namespace)
+    emitBlock(N, FieldId::F_namespace);
+  for (const auto &CI : I.Description)
+    emitBlock(CI);
   if (I.DefLoc)
     emitRecord(I.DefLoc.getValue(), RECORD_DEFLOCATION);
   for (const auto &L : I.Loc)
@@ -467,7 +476,12 @@ void ClangDocBitcodeWriter::emitBlock(co
 
 void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
   StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
-  EMITINFO(FUNCTION)
+  emitRecord(I.USR, FUNCTION_USR);
+  emitRecord(I.Name, FUNCTION_NAME);
+  for (const auto &N : I.Namespace)
+    emitBlock(N, FieldId::F_namespace);
+  for (const auto &CI : I.Description)
+    emitBlock(CI);
   emitRecord(I.IsMethod, FUNCTION_IS_METHOD);
   if (I.DefLoc)
     emitRecord(I.DefLoc.getValue(), FUNCTION_DEFLOCATION);
@@ -479,7 +493,26 @@ void ClangDocBitcodeWriter::emitBlock(co
     emitBlock(N);
 }
 
-#undef EMITINFO
+bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
+  switch (I->IT) {
+  case InfoType::IT_namespace:
+    emitBlock(*static_cast<clang::doc::NamespaceInfo *>(I));
+    break;
+  case InfoType::IT_record:
+    emitBlock(*static_cast<clang::doc::RecordInfo *>(I));
+    break;
+  case InfoType::IT_enum:
+    emitBlock(*static_cast<clang::doc::EnumInfo *>(I));
+    break;
+  case InfoType::IT_function:
+    emitBlock(*static_cast<clang::doc::FunctionInfo *>(I));
+    break;
+  default:
+    llvm::errs() << "Unexpected info, unable to write.\n";
+    return true;
+  }
+  return false;
+}
 
 } // namespace doc
 } // namespace clang

Modified: clang-tools-extra/trunk/clang-doc/BitcodeWriter.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.h?rev=333932&r1=333931&r2=333932&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeWriter.h (original)
+++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.h Mon Jun  4 10:22:20 2018
@@ -34,7 +34,7 @@ namespace doc {
 static const unsigned VersionNumber = 2;
 
 struct BitCodeConstants {
-  static constexpr unsigned RecordSize = 16U;
+  static constexpr unsigned RecordSize = 32U;
   static constexpr unsigned SignatureBitSize = 8U;
   static constexpr unsigned SubblockIDSize = 4U;
   static constexpr unsigned BoolSize = 1U;
@@ -45,6 +45,8 @@ struct BitCodeConstants {
   static constexpr unsigned ReferenceTypeSize = 8U;
   static constexpr unsigned USRLengthSize = 6U;
   static constexpr unsigned USRBitLengthSize = 8U;
+  static constexpr char Signature[4] = {'D', 'O', 'C', 'S'};
+  static constexpr int USRHashSize = 20;
 };
 
 // New Ids need to be added to both the enum here and the relevant IdNameMap in
@@ -113,7 +115,7 @@ static constexpr unsigned RecordIdCount
 #undef INFORECORDS
 
 // Identifiers for differentiating between subblocks
-enum class FieldId { F_namespace = 1, F_parent, F_vparent, F_type };
+enum class FieldId { F_default, F_namespace, F_parent, F_vparent, F_type };
 
 class ClangDocBitcodeWriter {
 public:
@@ -123,12 +125,8 @@ public:
     emitVersionBlock();
   }
 
-#ifndef NDEBUG // Don't want explicit dtor unless needed.
-  ~ClangDocBitcodeWriter() {
-    // Check that the static size is large-enough.
-    assert(Record.capacity() > BitCodeConstants::RecordSize);
-  }
-#endif
+  // Write a specific info to a bitcode stream.
+  bool dispatchInfoForWrite(Info *I);
 
   // Block emission of different info types.
   void emitBlock(const NamespaceInfo &I);

Modified: clang-tools-extra/trunk/clang-doc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/CMakeLists.txt?rev=333932&r1=333931&r2=333932&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-doc/CMakeLists.txt Mon Jun  4 10:22:20 2018
@@ -3,9 +3,11 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_clang_library(clangDoc
+  BitcodeReader.cpp
   BitcodeWriter.cpp
   ClangDoc.cpp
   Mapper.cpp
+  Representation.cpp
   Serialize.cpp
 
   LINK_LIBS

Added: clang-tools-extra/trunk/clang-doc/Representation.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.cpp?rev=333932&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.cpp (added)
+++ clang-tools-extra/trunk/clang-doc/Representation.cpp Mon Jun  4 10:22:20 2018
@@ -0,0 +1,131 @@
+///===-- Representation.cpp - ClangDoc Representation -----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the merging of different types of infos. The data in the
+// calling Info is preserved during a merge unless that field is empty or
+// default. In that case, the data from the parameter Info is used to replace
+// the empty or default data.
+//
+// For most fields, the first decl seen provides the data. Exceptions to this
+// include the location and description fields, which are collections of data on
+// all decls related to a given definition. All other fields are ignored in new
+// decls unless the first seen decl didn't, for whatever reason, incorporate
+// data on that field (e.g. a forward declared class wouldn't have information
+// on members on the forward declaration, but would have the class name).
+//
+//===----------------------------------------------------------------------===//
+#include "Representation.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace doc {
+
+static const SymbolID EmptySID = SymbolID();
+
+template <typename T>
+std::unique_ptr<Info> reduce(std::vector<std::unique_ptr<Info>> &Values) {
+  std::unique_ptr<Info> Merged = llvm::make_unique<T>();
+  T *Tmp = static_cast<T *>(Merged.get());
+  for (auto &I : Values)
+    Tmp->merge(std::move(*static_cast<T *>(I.get())));
+  return Merged;
+}
+
+// Dispatch function.
+llvm::Expected<std::unique_ptr<Info>>
+mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
+  if (Values.empty())
+    return llvm::make_error<llvm::StringError>("No info values to merge.\n",
+                                             llvm::inconvertibleErrorCode());
+
+  switch (Values[0]->IT) {
+  case InfoType::IT_namespace:
+    return reduce<NamespaceInfo>(Values);
+  case InfoType::IT_record:
+    return reduce<RecordInfo>(Values);
+  case InfoType::IT_enum:
+    return reduce<EnumInfo>(Values);
+  case InfoType::IT_function:
+    return reduce<FunctionInfo>(Values);
+  default:
+    return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
+                                               llvm::inconvertibleErrorCode());
+  }
+}
+
+void Info::mergeBase(Info &&Other) {
+  assert(mergeable(Other));
+  if (USR == EmptySID)
+    USR = Other.USR;
+  if (Name == "")
+    Name = Other.Name;
+  if (Namespace.empty())
+    Namespace = std::move(Other.Namespace);
+  // Unconditionally extend the description, since each decl may have a comment.
+  std::move(Other.Description.begin(), Other.Description.end(),
+            std::back_inserter(Description));
+}
+
+bool Info::mergeable(const Info &Other) {
+  return IT == Other.IT && (USR == EmptySID || USR == Other.USR);
+}
+
+void SymbolInfo::merge(SymbolInfo &&Other) {
+  assert(mergeable(Other));
+  if (!DefLoc)
+    DefLoc = std::move(Other.DefLoc);
+  // Unconditionally extend the list of locations, since we want all of them.
+  std::move(Other.Loc.begin(), Other.Loc.end(), std::back_inserter(Loc));
+  mergeBase(std::move(Other));
+}
+
+void NamespaceInfo::merge(NamespaceInfo &&Other) {
+  assert(mergeable(Other));
+  mergeBase(std::move(Other));
+}
+
+void RecordInfo::merge(RecordInfo &&Other) {
+  assert(mergeable(Other));
+  if (!TagType)
+    TagType = Other.TagType;
+  if (Members.empty())
+    Members = std::move(Other.Members);
+  if (Parents.empty())
+    Parents = std::move(Other.Parents);
+  if (VirtualParents.empty())
+    VirtualParents = std::move(Other.VirtualParents);
+  SymbolInfo::merge(std::move(Other));
+}
+
+void EnumInfo::merge(EnumInfo &&Other) {
+  assert(mergeable(Other));
+  if (!Scoped)
+    Scoped = Other.Scoped;
+  if (Members.empty())
+    Members = std::move(Other.Members);
+  SymbolInfo::merge(std::move(Other));
+}
+
+void FunctionInfo::merge(FunctionInfo &&Other) {
+  assert(mergeable(Other));
+  if (!IsMethod)
+    IsMethod = Other.IsMethod;
+  if (!Access)
+    Access = Other.Access;
+  if (ReturnType.Type.USR == EmptySID && ReturnType.Type.Name == "")
+    ReturnType = std::move(Other.ReturnType);
+  if (Parent.USR == EmptySID && Parent.Name == "")
+    Parent = std::move(Other.Parent);
+  if (Params.empty())
+    Params = std::move(Other.Params);
+  SymbolInfo::merge(std::move(Other));
+}
+
+} // namespace doc
+} // namespace clang

Modified: clang-tools-extra/trunk/clang-doc/Representation.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.h?rev=333932&r1=333931&r2=333932&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.h (original)
+++ clang-tools-extra/trunk/clang-doc/Representation.h Mon Jun  4 10:22:20 2018
@@ -1,4 +1,4 @@
-///===-- Representation.h - ClangDoc Represenation --------------*- C++ -*-===//
+///===-- Representation.h - ClangDoc Representation -------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -26,6 +26,7 @@
 namespace clang {
 namespace doc {
 
+// SHA1'd hash of a USR.
 using SymbolID = std::array<uint8_t, 20>;
 
 struct Info;
@@ -40,7 +41,8 @@ enum class InfoType {
 // A representation of a parsed comment.
 struct CommentInfo {
   CommentInfo() = default;
-  CommentInfo(CommentInfo &&Other) : Children(std::move(Other.Children)) {}
+  CommentInfo(CommentInfo &Other) = delete;
+  CommentInfo(CommentInfo &&Other) = default;
 
   SmallString<16> Kind; // Kind of comment (TextComment, InlineCommandComment,
                         // HTMLStartTagComment, HTMLEndTagComment,
@@ -128,21 +130,35 @@ struct Location {
 /// A base struct for Infos.
 struct Info {
   Info() = default;
-  Info(Info &&Other) : Description(std::move(Other.Description)) {}
-  virtual ~Info() = default;
-
-  SymbolID USR; // Unique identifier for the decl described by this Info.
-  SmallString<16> Name; // Unqualified name of the decl.
+  Info(InfoType IT) : IT(IT) {}
+  Info(const Info &Other) = delete;
+  Info(Info &&Other) = default;
+
+  SymbolID USR =
+      SymbolID(); // Unique identifier for the decl described by this Info.
+  const InfoType IT = InfoType::IT_default; // InfoType of this particular Info.
+  SmallString<16> Name;                     // Unqualified name of the decl.
   llvm::SmallVector<Reference, 4>
       Namespace; // List of parent namespaces for this decl.
   std::vector<CommentInfo> Description; // Comment description of this decl.
+
+  void mergeBase(Info &&I);
+  bool mergeable(const Info &Other);
 };
 
 // Info for namespaces.
-struct NamespaceInfo : public Info {};
+struct NamespaceInfo : public Info {
+  NamespaceInfo() : Info(InfoType::IT_namespace) {}
+
+  void merge(NamespaceInfo &&I);
+};
 
 // Info for symbols.
 struct SymbolInfo : public Info {
+  SymbolInfo(InfoType IT) : Info(IT) {}
+
+  void merge(SymbolInfo &&I);
+
   llvm::Optional<Location> DefLoc;    // Location where this decl is defined.
   llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
 };
@@ -150,6 +166,10 @@ struct SymbolInfo : public Info {
 // TODO: Expand to allow for documenting templating and default args.
 // Info for functions.
 struct FunctionInfo : public SymbolInfo {
+  FunctionInfo() : SymbolInfo(InfoType::IT_function) {}
+
+  void merge(FunctionInfo &&I);
+
   bool IsMethod = false; // Indicates whether this function is a class method.
   Reference Parent;      // Reference to the parent class decl for this method.
   TypeInfo ReturnType;   // Info about the return type of this function.
@@ -163,12 +183,18 @@ struct FunctionInfo : public SymbolInfo
 // friend classes
 // Info for types.
 struct RecordInfo : public SymbolInfo {
-  TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record (struct,
-                                                 // class, union, interface).
+  RecordInfo() : SymbolInfo(InfoType::IT_record) {}
+
+  void merge(RecordInfo &&I);
+
+  TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record
+                                                 // (struct, class, union,
+                                                 // interface).
   llvm::SmallVector<MemberTypeInfo, 4>
       Members;                             // List of info about record members.
-  llvm::SmallVector<Reference, 4> Parents; // List of base/parent records (does
-                                           // not include virtual parents).
+  llvm::SmallVector<Reference, 4> Parents; // List of base/parent records
+                                           // (does not include virtual
+                                           // parents).
   llvm::SmallVector<Reference, 4>
       VirtualParents; // List of virtual base/parent records.
 };
@@ -176,6 +202,10 @@ struct RecordInfo : public SymbolInfo {
 // TODO: Expand to allow for documenting templating.
 // Info for types.
 struct EnumInfo : public SymbolInfo {
+  EnumInfo() : SymbolInfo(InfoType::IT_enum) {}
+
+  void merge(EnumInfo &&I);
+
   bool Scoped =
       false; // Indicates whether this enum is scoped (e.g. enum class).
   llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members.
@@ -183,6 +213,12 @@ struct EnumInfo : public SymbolInfo {
 
 // TODO: Add functionality to include separate markdown pages.
 
+// A standalone function to call to merge a vector of infos into one.
+// This assumes that all infos in the vector are of the same type, and will fail
+// if they are different.
+llvm::Expected<std::unique_ptr<Info>>
+mergeInfos(std::vector<std::unique_ptr<Info>> &Values);
+
 } // namespace doc
 } // namespace clang
 

Modified: clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp?rev=333932&r1=333931&r2=333932&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp Mon Jun  4 10:22:20 2018
@@ -18,7 +18,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "BitcodeReader.h"
+#include "BitcodeWriter.h"
 #include "ClangDoc.h"
+#include "Representation.h"
 #include "clang/AST/AST.h"
 #include "clang/AST/Decl.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -30,6 +33,7 @@
 #include "clang/Tooling/StandaloneExecution.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/ADT/APFloat.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
@@ -54,14 +58,66 @@ static llvm::cl::opt<bool>
                      llvm::cl::desc("Dump mapper results to bitcode file."),
                      llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
 
+static llvm::cl::opt<bool> DumpIntermediateResult(
+    "dump-intermediate",
+    llvm::cl::desc("Dump intermediate results to bitcode file."),
+    llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
+
+enum OutputFormatTy {
+  yaml,
+};
+
+static llvm::cl::opt<OutputFormatTy>
+    Format("format", llvm::cl::desc("Format for outputted docs."),
+           llvm::cl::values(clEnumVal(yaml, "Documentation in YAML format.")),
+           llvm::cl::init(yaml), llvm::cl::cat(ClangDocCategory));
+
 static llvm::cl::opt<bool> DoxygenOnly(
     "doxygen",
     llvm::cl::desc("Use only doxygen-style comments to generate docs."),
     llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
 
+bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) {
+  std::error_code OK;
+  llvm::SmallString<128> DocsRootPath;
+  if (ClearDirectory) {
+    std::error_code RemoveStatus = llvm::sys::fs::remove_directories(DirName);
+    if (RemoveStatus != OK) {
+      llvm::errs() << "Unable to remove existing documentation directory for "
+                   << DirName << ".\n";
+      return true;
+    }
+  }
+  std::error_code DirectoryStatus = llvm::sys::fs::create_directories(DirName);
+  if (DirectoryStatus != OK) {
+    llvm::errs() << "Unable to create documentation directories.\n";
+    return true;
+  }
+  return false;
+}
+
+bool DumpResultToFile(const Twine &DirName, const Twine &FileName,
+                      StringRef Buffer, bool ClearDirectory = false) {
+  std::error_code OK;
+  llvm::SmallString<128> IRRootPath;
+  llvm::sys::path::native(OutDirectory, IRRootPath);
+  llvm::sys::path::append(IRRootPath, DirName);
+  if (CreateDirectory(IRRootPath, ClearDirectory))
+    return true;
+  llvm::sys::path::append(IRRootPath, FileName);
+  std::error_code OutErrorInfo;
+  llvm::raw_fd_ostream OS(IRRootPath, OutErrorInfo, llvm::sys::fs::F_None);
+  if (OutErrorInfo != OK) {
+    llvm::errs() << "Error opening documentation file.\n";
+    return true;
+  }
+  OS << Buffer;
+  OS.close();
+  return false;
+}
+
 int main(int argc, const char **argv) {
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
-  std::error_code OK;
 
   auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
       argc, argv, ClangDocCategory);
@@ -80,34 +136,66 @@ int main(int argc, const char **argv) {
 
   // Mapping phase
   llvm::outs() << "Mapping decls...\n";
-  auto Err = Exec->get()->execute(doc::newMapperActionFactory(
-                                      Exec->get()->getExecutionContext()),
-                                  ArgAdjuster);
-  if (Err)
+  auto Err = Exec->get()->execute(
+      doc::newMapperActionFactory(Exec->get()->getExecutionContext()),
+      ArgAdjuster);
+  if (Err) {
     llvm::errs() << toString(std::move(Err)) << "\n";
+    return 1;
+  }
 
   if (DumpMapperResult) {
-    Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
-                                                     StringRef Value) {
-      SmallString<128> IRRootPath;
-      llvm::sys::path::native(OutDirectory, IRRootPath);
-      llvm::sys::path::append(IRRootPath, "bc");
-      std::error_code DirectoryStatus =
-          llvm::sys::fs::create_directories(IRRootPath);
-      if (DirectoryStatus != OK) {
-        llvm::errs() << "Unable to create documentation directories.\n";
-        return;
-      }
-      llvm::sys::path::append(IRRootPath, Key + ".bc");
-      std::error_code OutErrorInfo;
-      llvm::raw_fd_ostream OS(IRRootPath, OutErrorInfo, llvm::sys::fs::F_None);
-      if (OutErrorInfo != OK) {
-        llvm::errs() << "Error opening documentation file.\n";
-        return;
+    bool Err = false;
+    Exec->get()->getToolResults()->forEachResult(
+        [&](StringRef Key, StringRef Value) {
+          Err = DumpResultToFile("bc", Key + ".bc", Value);
+        });
+    if (Err)
+      llvm::errs() << "Error dumping map results.\n";
+    return Err;
+  }
+
+  // Collect values into output by key.
+  llvm::outs() << "Collecting infos...\n";
+  llvm::StringMap<std::vector<std::unique_ptr<doc::Info>>> MapOutput;
+
+  // In ToolResults, the Key is the hashed USR and the value is the
+  // bitcode-encoded representation of the Info object.
+  Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
+                                                   StringRef Value) {
+    llvm::BitstreamCursor Stream(Value);
+    doc::ClangDocBitcodeReader Reader(Stream);
+    auto Infos = Reader.readBitcode();
+    for (auto &I : Infos) {
+      auto R =
+          MapOutput.try_emplace(Key, std::vector<std::unique_ptr<doc::Info>>());
+      R.first->second.emplace_back(std::move(I));
+    }
+  });
+
+  // Reducing phase
+  llvm::outs() << "Reducing " << MapOutput.size() << " infos...\n";
+  llvm::StringMap<std::unique_ptr<doc::Info>> ReduceOutput;
+  for (auto &Group : MapOutput) {
+    auto Reduced = doc::mergeInfos(Group.getValue());
+    if (!Reduced)
+      llvm::errs() << llvm::toString(Reduced.takeError());
+
+    if (DumpIntermediateResult) {
+      SmallString<4096> Buffer;
+      llvm::BitstreamWriter Stream(Buffer);
+      doc::ClangDocBitcodeWriter Writer(Stream);
+      Writer.dispatchInfoForWrite(Reduced.get().get());
+      if (DumpResultToFile("bc", Group.getKey() + ".bc", Buffer)) {
+        llvm::errs() << "Error writing " << Group.getKey() << " to file.\n";
+        continue;
       }
-      OS << Value;
-      OS.close();
-    });
+    }
+
+    ReduceOutput.insert(
+        std::make_pair(Group.getKey(), std::move(Reduced.get())));
+
+    // FIXME: Add support for emitting different output formats.
   }
 
   return 0;

Added: clang-tools-extra/trunk/test/clang-doc/bc-comment.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/bc-comment.cpp?rev=333932&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-doc/bc-comment.cpp (added)
+++ clang-tools-extra/trunk/test/clang-doc/bc-comment.cpp Mon Jun  4 10:22:20 2018
@@ -0,0 +1,197 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-intermediate -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/7574630614A535710E5A6ABCFFF98BCA2D06A4CA.bc --dump | FileCheck %s
+ 
+/// \brief Brief description.
+///
+/// Extended description that
+/// continues onto the next line.
+/// 
+/// <ul class="test">
+///   <li> Testing.
+/// </ul>
+///
+/// \verbatim
+/// The description continues.
+/// \endverbatim
+/// --
+/// \param [out] I is a parameter.
+/// \param J is a parameter.
+/// \return void
+void F(int I, int J);
+
+/// Bonus comment on definition
+void F(int I, int J) {}
+
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK-NEXT: <VersionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-NEXT: </VersionBlock>
+// CHECK-NEXT: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=117 op2=116 op3=99 op4=6 op5=20 op6=165 op7=53 op8=113 op9=14 op10=90 op11=106 op12=188 op13=255 op14=249 op15=139 op16=202 op17=45 op18=6 op19=164 op20=202/>
+  // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
+  // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment'
+      // CHECK-NEXT: <Name abbrevid=6 op0=5/> blob data = 'brief'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+        // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+          // CHECK-NEXT: <Text abbrevid=5 op0=19/> blob data = ' Brief description.'
+        // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=26/> blob data = ' Extended description that'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=30/> blob data = ' continues onto the next line.'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment'
+        // CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul'
+        // CHECK-NEXT: <AttrKey abbrevid=12 op0=5/> blob data = 'class'
+        // CHECK-NEXT: <AttrVal abbrevid=13 op0=4/> blob data = 'test'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment'
+        // CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'li'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=9/> blob data = ' Testing.'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=17/> blob data = 'HTMLEndTagComment'
+        // CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul'
+        // CHECK-NEXT: <SelfClosing abbrevid=10 op0=1/>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=20/> blob data = 'VerbatimBlockComment'
+      // CHECK-NEXT: <Name abbrevid=6 op0=8/> blob data = 'verbatim'
+      // CHECK-NEXT: <CloseName abbrevid=9 op0=11/> blob data = 'endverbatim'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=24/> blob data = 'VerbatimBlockLineComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=27/> blob data = ' The description continues.'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=3/> blob data = ' --'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment'
+      // CHECK-NEXT: <Direction abbrevid=7 op0=5/> blob data = '[out]'
+      // CHECK-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'I'
+      // CHECK-NEXT: <Explicit abbrevid=11 op0=1/>
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+        // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+          // CHECK-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.'
+        // CHECK-NEXT: </CommentBlock>
+        // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment'
+      // CHECK-NEXT: <Direction abbrevid=7 op0=4/> blob data = '[in]'
+      // CHECK-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'J'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+        // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+          // CHECK-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.'
+        // CHECK-NEXT: </CommentBlock>
+        // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment'
+      // CHECK-NEXT: <Name abbrevid=6 op0=6/> blob data = 'return'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+        // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+          // CHECK-NEXT: <Text abbrevid=5 op0=5/> blob data = ' void'
+        // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+  // CHECK-NEXT: </CommentBlock>
+  // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
+    // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=28/> blob data = ' Bonus comment on definition'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+  // CHECK-NEXT: </CommentBlock>
+  // CHECK-NEXT: <DefLocation abbrevid=6 op0=27 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-NEXT: <Location abbrevid=7 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+      // CHECK-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-NEXT: </ReferenceBlock>
+  // CHECK-NEXT: </TypeBlock>
+  // CHECK-NEXT: <FieldTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+      // CHECK-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-NEXT: </ReferenceBlock>
+    // CHECK-NEXT: <Name abbrevid=4 op0=1/> blob data = 'I'
+  // CHECK-NEXT: </FieldTypeBlock>
+  // CHECK-NEXT: <FieldTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+      // CHECK-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-NEXT: </ReferenceBlock>
+    // CHECK-NEXT: <Name abbrevid=4 op0=1/> blob data = 'J'
+  // CHECK-NEXT: </FieldTypeBlock>
+// CHECK-NEXT: </FunctionBlock>

Added: clang-tools-extra/trunk/test/clang-doc/bc-namespace.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/bc-namespace.cpp?rev=333932&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-doc/bc-namespace.cpp (added)
+++ clang-tools-extra/trunk/test/clang-doc/bc-namespace.cpp Mon Jun  4 10:22:20 2018
@@ -0,0 +1,109 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-intermediate -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/8D042EFFC98B373450BC6B5B90A330C25A150E9C.bc --dump | FileCheck %s --check-prefix CHECK-A
+// RUN: llvm-bcanalyzer %t/docs/bc/E21AF79E2A9D02554BA090D10DF39FE273F5CDB5.bc --dump | FileCheck %s --check-prefix CHECK-B
+// RUN: llvm-bcanalyzer %t/docs/bc/39D3C95A5F7CE2BA4937BD7B01BAE09EBC2AD8AC.bc --dump | FileCheck %s --check-prefix CHECK-F
+// RUN: llvm-bcanalyzer %t/docs/bc/9A82CB33ED0FDF81EE383D31CD0957D153C5E840.bc --dump | FileCheck %s --check-prefix CHECK-FUNC
+// RUN: llvm-bcanalyzer %t/docs/bc/E9ABF7E7E2425B626723D41E76E4BC7E7A5BD775.bc --dump | FileCheck %s --check-prefix CHECK-E
+ 
+namespace A {
+// CHECK-A: <NamespaceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-A-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+  // CHECK-A-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-A-NEXT: </NamespaceBlock>
+  
+void f();
+
+}  // namespace A
+
+namespace A {
+
+void f(){};
+// CHECK-F: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=57 op2=211 op3=201 op4=90 op5=95 op6=124 op7=226 op8=186 op9=73 op10=55 op11=189 op12=123 op13=1 op14=186 op15=224 op16=158 op17=188 op18=42 op19=216 op20=172/>
+  // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'f'
+  // CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+    // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+    // CHECK-F-NEXT: <RefType abbrevid=6 op0=1/>
+    // CHECK-F-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-F-NEXT: </ReferenceBlock>
+  // CHECK-F-NEXT: <DefLocation abbrevid=6 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-F-NEXT: <Location abbrevid=7 op0=18 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-F-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-F-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+      // CHECK-F-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-F-NEXT: </ReferenceBlock>
+  // CHECK-F-NEXT: </TypeBlock>
+// CHECK-F-NEXT: </FunctionBlock>
+
+namespace B {
+// CHECK-B: <NamespaceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-B-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
+  // CHECK-B-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+  // CHECK-B-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-B-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+    // CHECK-B-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+    // CHECK-B-NEXT: <RefType abbrevid=6 op0=1/>
+    // CHECK-B-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-B-NEXT: </ReferenceBlock>
+// CHECK-B-NEXT: </NamespaceBlock>
+
+enum E { X };
+// CHECK-E: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=233 op2=171 op3=247 op4=231 op5=226 op6=66 op7=91 op8=98 op9=103 op10=35 op11=212 op12=30 op13=118 op14=228 op15=188 op16=126 op17=122 op18=91 op19=215 op20=117/>
+  // CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+  // CHECK-E-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
+    // CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+    // CHECK-E-NEXT: <RefType abbrevid=6 op0=1/>
+    // CHECK-E-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-E-NEXT: </ReferenceBlock>
+  // CHECK-E-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+    // CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+    // CHECK-E-NEXT: <RefType abbrevid=6 op0=1/>
+    // CHECK-E-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-E-NEXT: </ReferenceBlock>
+  // CHECK-E-NEXT: <DefLocation abbrevid=6 op0=56 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-E-NEXT: <Member abbrevid=8 op0=1/> blob data = 'X'
+// CHECK-E-NEXT: </EnumBlock>
+
+E func(int i) { return X; }
+// CHECK-FUNC: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-FUNC-NEXT: <USR abbrevid=4 op0=20 op1=154 op2=130 op3=203 op4=51 op5=237 op6=15 op7=223 op8=129 op9=238 op10=56 op11=61 op12=49 op13=205 op14=9 op15=87 op16=209 op17=83 op18=197 op19=232 op20=64/>
+  // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=4/> blob data = 'func'
+  // CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-FUNC-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
+    // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+    // CHECK-FUNC-NEXT: <RefType abbrevid=6 op0=1/>
+    // CHECK-FUNC-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-FUNC-NEXT: </ReferenceBlock>
+  // CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-FUNC-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+    // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+    // CHECK-FUNC-NEXT: <RefType abbrevid=6 op0=1/>
+    // CHECK-FUNC-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-FUNC-NEXT: </ReferenceBlock>
+  // CHECK-FUNC-NEXT: <DefLocation abbrevid=6 op0=76 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-FUNC-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=12/> blob data = 'enum A::B::E'
+      // CHECK-FUNC-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-FUNC-NEXT: </ReferenceBlock>
+  // CHECK-FUNC-NEXT: </TypeBlock>
+  // CHECK-FUNC-NEXT: <FieldTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-FUNC-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+      // CHECK-FUNC-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-FUNC-NEXT: </ReferenceBlock>
+    // CHECK-FUNC-NEXT: <Name abbrevid=4 op0=1/> blob data = 'i'
+  // CHECK-FUNC-NEXT: </FieldTypeBlock>
+// CHECK-FUNC-NEXT: </FunctionBlock>
+
+}  // namespace B
+}  // namespace A

Added: clang-tools-extra/trunk/test/clang-doc/bc-record.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/bc-record.cpp?rev=333932&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-doc/bc-record.cpp (added)
+++ clang-tools-extra/trunk/test/clang-doc/bc-record.cpp Mon Jun  4 10:22:20 2018
@@ -0,0 +1,254 @@
+// This test requires Linux due to the system-dependent USR for the
+// inner class in function H.
+// REQUIRES: system-linux
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-intermediate -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/ACE81AFA6627B4CEF2B456FB6E1252925674AF7E.bc --dump | FileCheck %s --check-prefix CHECK-A
+// RUN: llvm-bcanalyzer %t/docs/bc/FC07BD34D5E77782C263FA944447929EA8753740.bc --dump | FileCheck %s --check-prefix CHECK-B
+// RUN: llvm-bcanalyzer %t/docs/bc/1E3438A08BA22025C0B46289FF0686F92C8924C5.bc --dump | FileCheck %s --check-prefix CHECK-BC
+// RUN: llvm-bcanalyzer %t/docs/bc/06B5F6A19BA9F6A832E127C9968282B94619B210.bc --dump | FileCheck %s --check-prefix CHECK-C
+// RUN: llvm-bcanalyzer %t/docs/bc/0921737541208B8FA9BB42B60F78AC1D779AA054.bc --dump | FileCheck %s --check-prefix CHECK-D
+// RUN: llvm-bcanalyzer %t/docs/bc/289584A8E0FF4178A794622A547AA622503967A1.bc --dump | FileCheck %s --check-prefix CHECK-E
+// RUN: llvm-bcanalyzer %t/docs/bc/DEB4AC1CD9253CD9EF7FBE6BCAC506D77984ABD4.bc --dump | FileCheck %s --check-prefix CHECK-ECON
+// RUN: llvm-bcanalyzer %t/docs/bc/BD2BDEBD423F80BACCEA75DE6D6622D355FC2D17.bc --dump | FileCheck %s --check-prefix CHECK-EDES
+// RUN: llvm-bcanalyzer %t/docs/bc/E3B54702FABFF4037025BA194FC27C47006330B5.bc --dump | FileCheck %s --check-prefix CHECK-F
+// RUN: llvm-bcanalyzer %t/docs/bc/B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E.bc --dump | FileCheck %s --check-prefix CHECK-H
+// RUN: llvm-bcanalyzer %t/docs/bc/6BA1EE2B3DAEACF6E4306F10AF44908F4807927C.bc --dump | FileCheck %s --check-prefix CHECK-I
+// RUN: llvm-bcanalyzer %t/docs/bc/5093D428CDC62096A67547BA52566E4FB9404EEE.bc --dump | FileCheck %s --check-prefix CHECK-PM
+// RUN: llvm-bcanalyzer %t/docs/bc/CA7C7935730B5EACD25F080E9C83FA087CCDC75E.bc --dump | FileCheck %s --check-prefix CHECK-X
+// RUN: llvm-bcanalyzer %t/docs/bc/641AB4A3D36399954ACDE29C7A8833032BF40472.bc --dump | FileCheck %s --check-prefix CHECK-Y
+
+void H() {
+  class I {};
+}
+// CHECK-H: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-H-NEXT: <USR abbrevid=4 op0=20 op1=182 op2=172 op3=76 op4=92 op5=159 op6=46 op7=163 op8=242 op9=179 op10=236 op11=225 op12=163 op13=61 op14=52 op15=159 op16=78 op17=229 op18=2 op19=178 op20=78/>
+  // CHECK-H-NEXT: <Name abbrevid=5 op0=1/> blob data = 'H'
+  // CHECK-H-NEXT: <DefLocation abbrevid=6 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-H-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-H-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-H-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+      // CHECK-H-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-H-NEXT: </ReferenceBlock>
+  // CHECK-H-NEXT: </TypeBlock>
+// CHECK-H-NEXT: </FunctionBlock>
+
+
+// CHECK-I: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-I-NEXT: <USR abbrevid=4 op0=20 op1=107 op2=161 op3=238 op4=43 op5=61 op6=174 op7=172 op8=246 op9=228 op10=48 op11=111 op12=16 op13=175 op14=68 op15=144 op16=143 op17=72 op18=7 op19=146 op20=124/>
+  // CHECK-I-NEXT: <Name abbrevid=5 op0=1/> blob data = 'I'
+  // CHECK-I-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-I-NEXT: <USR abbrevid=4 op0=20 op1=182 op2=172 op3=76 op4=92 op5=159 op6=46 op7=163 op8=242 op9=179 op10=236 op11=225 op12=163 op13=61 op14=52 op15=159 op16=78 op17=229 op18=2 op19=178 op20=78/>
+    // CHECK-I-NEXT: <Name abbrevid=5 op0=1/> blob data = 'H'
+    // CHECK-I-NEXT: <RefType abbrevid=6 op0=3/>
+    // CHECK-I-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-I-NEXT: </ReferenceBlock>
+  // CHECK-I-NEXT: <DefLocation abbrevid=6 op0=25 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-I-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-I-NEXT: </RecordBlock>
+
+union A { int X; int Y; };
+// CHECK-A: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-A-NEXT: <USR abbrevid=4 op0=20 op1=172 op2=232 op3=26 op4=250 op5=102 op6=39 op7=180 op8=206 op9=242 op10=180 op11=86 op12=251 op13=110 op14=18 op15=82 op16=146 op17=86 op18=116 op19=175 op20=126/>
+  // CHECK-A-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+  // CHECK-A-NEXT: <DefLocation abbrevid=6 op0=53 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-A-NEXT: <TagType abbrevid=8 op0=2/>
+  // CHECK-A-NEXT: <MemberTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-A-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-A-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+      // CHECK-A-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-A-NEXT: </ReferenceBlock>
+    // CHECK-A-NEXT: <Name abbrevid=4 op0=1/> blob data = 'X'
+    // CHECK-A-NEXT: <Access abbrevid=5 op0=3/>
+  // CHECK-A-NEXT: </MemberTypeBlock>
+  // CHECK-A-NEXT: <MemberTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-A-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-A-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+      // CHECK-A-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-A-NEXT: </ReferenceBlock>
+    // CHECK-A-NEXT: <Name abbrevid=4 op0=1/> blob data = 'Y'
+    // CHECK-A-NEXT: <Access abbrevid=5 op0=3/>
+  // CHECK-A-NEXT: </MemberTypeBlock>
+// CHECK-A-NEXT: </RecordBlock>
+
+enum B { X, Y };
+// CHECK-B: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-B-NEXT: <USR abbrevid=4 op0=20 op1=252 op2=7 op3=189 op4=52 op5=213 op6=231 op7=119 op8=130 op9=194 op10=99 op11=250 op12=148 op13=68 op14=71 op15=146 op16=158 op17=168 op18=117 op19=55 op20=64/>
+  // CHECK-B-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+  // CHECK-B-NEXT: <DefLocation abbrevid=6 op0=77 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-B-NEXT: <Member abbrevid=8 op0=1/> blob data = 'X'
+  // CHECK-B-NEXT: <Member abbrevid=8 op0=1/> blob data = 'Y'
+// CHECK-B-NEXT: </EnumBlock>
+
+enum class Bc { A, B };
+// CHECK-BC: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-BC-NEXT: <USR abbrevid=4 op0=20 op1=30 op2=52 op3=56 op4=160 op5=139 op6=162 op7=32 op8=37 op9=192 op10=180 op11=98 op12=137 op13=255 op14=6 op15=134 op16=249 op17=44 op18=137 op19=36 op20=197/>
+  // CHECK-BC-NEXT: <Name abbrevid=5 op0=2/> blob data = 'Bc'
+  // CHECK-BC-NEXT: <DefLocation abbrevid=6 op0=86 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-BC-NEXT: <Scoped abbrevid=9 op0=1/>
+  // CHECK-BC-NEXT: <Member abbrevid=8 op0=1/> blob data = 'A'
+  // CHECK-BC-NEXT: <Member abbrevid=8 op0=1/> blob data = 'B'
+// CHECK-BC-NEXT: </EnumBlock>
+
+struct C { int i; };
+// CHECK-C: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-C-NEXT: <USR abbrevid=4 op0=20 op1=6 op2=181 op3=246 op4=161 op5=155 op6=169 op7=246 op8=168 op9=50 op10=225 op11=39 op12=201 op13=150 op14=130 op15=130 op16=185 op17=70 op18=25 op19=178 op20=16/>
+  // CHECK-C-NEXT: <Name abbrevid=5 op0=1/> blob data = 'C'
+  // CHECK-C-NEXT: <DefLocation abbrevid=6 op0=96 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-C-NEXT: <MemberTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-C-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-C-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+      // CHECK-C-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-C-NEXT: </ReferenceBlock>
+    // CHECK-C-NEXT: <Name abbrevid=4 op0=1/> blob data = 'i'
+    // CHECK-C-NEXT: <Access abbrevid=5 op0=3/>
+  // CHECK-C-NEXT: </MemberTypeBlock>
+// CHECK-C-NEXT: </RecordBlock>
+
+class D {};
+// CHECK-D: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-D-NEXT: <USR abbrevid=4 op0=20 op1=9 op2=33 op3=115 op4=117 op5=65 op6=32 op7=139 op8=143 op9=169 op10=187 op11=66 op12=182 op13=15 op14=120 op15=172 op16=29 op17=119 op18=154 op19=160 op20=84/>
+  // CHECK-D-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D'
+  // CHECK-D-NEXT: <DefLocation abbrevid=6 op0=111 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-D-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-D-NEXT: </RecordBlock>
+
+class E {
+public:
+  E() {}
+  ~E() {}
+
+protected:
+  void ProtectedMethod();
+};
+// CHECK-E: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+  // CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+  // CHECK-E-NEXT: <DefLocation abbrevid=6 op0=119 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-E-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-E-NEXT: </RecordBlock>
+
+// CHECK-ECON: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-ECON-NEXT: <USR abbrevid=4 op0=20 op1=222 op2=180 op3=172 op4=28 op5=217 op6=37 op7=60 op8=217 op9=239 op10=127 op11=190 op12=107 op13=202 op14=197 op15=6 op16=215 op17=121 op18=132 op19=171 op20=212/>
+  // CHECK-ECON-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+    // CHECK-ECON-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-ECON-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+      // CHECK-ECON-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+      // CHECK-ECON-NEXT: <RefType abbrevid=6 op0=2/>
+      // CHECK-ECON-NEXT: <Field abbrevid=7 op0=1/>
+    // CHECK-ECON-NEXT: </ReferenceBlock>
+  // CHECK-ECON-NEXT: <IsMethod abbrevid=9 op0=1/>
+  // CHECK-ECON-NEXT: <DefLocation abbrevid=6 op0=121 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-ECON-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-ECON-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+    // CHECK-ECON-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+    // CHECK-ECON-NEXT: <RefType abbrevid=6 op0=2/>
+    // CHECK-ECON-NEXT: <Field abbrevid=7 op0=2/>
+  // CHECK-ECON-NEXT: </ReferenceBlock>
+  // CHECK-ECON-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-ECON-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-ECON-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+      // CHECK-ECON-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-ECON-NEXT: </ReferenceBlock>
+  // CHECK-ECON-NEXT: </TypeBlock>
+// CHECK-ECON-NEXT: </FunctionBlock>
+
+// CHECK-EDES: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-EDES-NEXT: <USR abbrevid=4 op0=20 op1=189 op2=43 op3=222 op4=189 op5=66 op6=63 op7=128 op8=186 op9=204 op10=234 op11=117 op12=222 op13=109 op14=102 op15=34 op16=211 op17=85 op18=252 op19=45 op20=23/>
+  // CHECK-EDES-NEXT: <Name abbrevid=5 op0=2/> blob data = '~E'
+  // CHECK-EDES-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-EDES-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+    // CHECK-EDES-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+    // CHECK-EDES-NEXT: <RefType abbrevid=6 op0=2/>
+    // CHECK-EDES-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-EDES-NEXT: </ReferenceBlock>
+  // CHECK-EDES-NEXT: <IsMethod abbrevid=9 op0=1/>
+  // CHECK-EDES-NEXT: <DefLocation abbrevid=6 op0=122 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-EDES-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-EDES-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+    // CHECK-EDES-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+    // CHECK-EDES-NEXT: <RefType abbrevid=6 op0=2/>
+    // CHECK-EDES-NEXT: <Field abbrevid=7 op0=2/>
+  // CHECK-EDES-NEXT: </ReferenceBlock>
+  // CHECK-EDES-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-EDES-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-EDES-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+      // CHECK-EDES-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-EDES-NEXT: </ReferenceBlock>
+  // CHECK-EDES-NEXT: </TypeBlock>
+// CHECK-EDES-NEXT: </FunctionBlock>
+
+void E::ProtectedMethod() {}
+// CHECK-PM: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-PM-NEXT: <USR abbrevid=4 op0=20 op1=80 op2=147 op3=212 op4=40 op5=205 op6=198 op7=32 op8=150 op9=166 op10=117 op11=71 op12=186 op13=82 op14=86 op15=110 op16=79 op17=185 op18=64 op19=78 op20=238/>
+  // CHECK-PM-NEXT: <Name abbrevid=5 op0=15/> blob data = 'ProtectedMethod'
+  // CHECK-PM-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-PM-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+    // CHECK-PM-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+    // CHECK-PM-NEXT: <RefType abbrevid=6 op0=2/>
+    // CHECK-PM-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-PM-NEXT: </ReferenceBlock>
+  // CHECK-PM-NEXT: <IsMethod abbrevid=9 op0=1/>
+  // CHECK-PM-NEXT: <DefLocation abbrevid=6 op0=184 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-PM-NEXT: <Location abbrevid=7 op0=125 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-PM-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-PM-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+    // CHECK-PM-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+    // CHECK-PM-NEXT: <RefType abbrevid=6 op0=2/>
+    // CHECK-PM-NEXT: <Field abbrevid=7 op0=2/>
+  // CHECK-PM-NEXT: </ReferenceBlock>
+  // CHECK-PM-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-PM-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+      // CHECK-PM-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+      // CHECK-PM-NEXT: <Field abbrevid=7 op0=4/>
+    // CHECK-PM-NEXT: </ReferenceBlock>
+  // CHECK-PM-NEXT: </TypeBlock>
+// CHECK-PM-NEXT: </FunctionBlock>
+
+
+
+class F : virtual private D, public E {};
+// CHECK-F: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=227 op2=181 op3=71 op4=2 op5=250 op6=191 op7=244 op8=3 op9=112 op10=37 op11=186 op12=25 op13=79 op14=194 op15=124 op16=71 op17=0 op18=99 op19=48 op20=181/>
+  // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
+  // CHECK-F-NEXT: <DefLocation abbrevid=6 op0=213 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-F-NEXT: <TagType abbrevid=8 op0=3/>
+  // CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+    // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+    // CHECK-F-NEXT: <RefType abbrevid=6 op0=2/>
+    // CHECK-F-NEXT: <Field abbrevid=7 op0=2/>
+  // CHECK-F-NEXT: </ReferenceBlock>
+  // CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=9 op2=33 op3=115 op4=117 op5=65 op6=32 op7=139 op8=143 op9=169 op10=187 op11=66 op12=182 op13=15 op14=120 op15=172 op16=29 op17=119 op18=154 op19=160 op20=84/>
+    // CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D'
+    // CHECK-F-NEXT: <RefType abbrevid=6 op0=2/>
+    // CHECK-F-NEXT: <Field abbrevid=7 op0=3/>
+  // CHECK-F-NEXT: </ReferenceBlock>
+// CHECK-F-NEXT: </RecordBlock>
+
+class X {
+  class Y {};
+};
+// CHECK-X: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-X-NEXT: <USR abbrevid=4 op0=20 op1=202 op2=124 op3=121 op4=53 op5=115 op6=11 op7=94 op8=172 op9=210 op10=95 op11=8 op12=14 op13=156 op14=131 op15=250 op16=8 op17=124 op18=205 op19=199 op20=94/>
+  // CHECK-X-NEXT: <Name abbrevid=5 op0=1/> blob data = 'X'
+  // CHECK-X-NEXT: <DefLocation abbrevid=6 op0=233 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-X-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-X-NEXT: </RecordBlock>
+
+// CHECK-Y: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-Y-NEXT: <USR abbrevid=4 op0=20 op1=100 op2=26 op3=180 op4=163 op5=211 op6=99 op7=153 op8=149 op9=74 op10=205 op11=226 op12=156 op13=122 op14=136 op15=51 op16=3 op17=43 op18=244 op19=4 op20=114/>
+  // CHECK-Y-NEXT: <Name abbrevid=5 op0=1/> blob data = 'Y'
+  // CHECK-Y-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+    // CHECK-Y-NEXT: <USR abbrevid=4 op0=20 op1=202 op2=124 op3=121 op4=53 op5=115 op6=11 op7=94 op8=172 op9=210 op10=95 op11=8 op12=14 op13=156 op14=131 op15=250 op16=8 op17=124 op18=205 op19=199 op20=94/>
+    // CHECK-Y-NEXT: <Name abbrevid=5 op0=1/> blob data = 'X'
+    // CHECK-Y-NEXT: <RefType abbrevid=6 op0=2/>
+    // CHECK-Y-NEXT: <Field abbrevid=7 op0=1/>
+  // CHECK-Y-NEXT: </ReferenceBlock>
+  // CHECK-Y-NEXT: <DefLocation abbrevid=6 op0=234 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-Y-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-Y-NEXT: </RecordBlock>




More information about the cfe-commits mailing list