[clang-tools-extra] r328270 - [clang-doc] Reland "[clang-doc] Setup clang-doc frontend framework"

Mikael Holmén via cfe-commits cfe-commits at lists.llvm.org
Sun Mar 25 23:49:44 PDT 2018


Hi Julie

If I compile without asserts this patch gives me

../tools/clang/tools/extra/clang-doc/BitcodeWriter.cpp:260:15: error: 
unused variable 'BlockIdName' [-Werror,-Wunused-variable]
   const auto &BlockIdName = BlockIdNameMap[BID];
               ^
1 error generated.

Regards,
Mikael

On 03/23/2018 12:34 AM, Julie Hockett via cfe-commits wrote:
> Author: juliehockett
> Date: Thu Mar 22 16:34:46 2018
> New Revision: 328270
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=328270&view=rev
> Log:
> [clang-doc] Reland "[clang-doc] Setup clang-doc frontend framework"
> 
> Fixed windows release build tests.
> 
> Added:
>      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/ClangDoc.cpp
>      clang-tools-extra/trunk/clang-doc/ClangDoc.h
>      clang-tools-extra/trunk/clang-doc/Mapper.cpp
>      clang-tools-extra/trunk/clang-doc/Mapper.h
>      clang-tools-extra/trunk/clang-doc/Representation.h
>      clang-tools-extra/trunk/clang-doc/Serialize.cpp
>      clang-tools-extra/trunk/clang-doc/Serialize.h
>      clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt
>      clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-class-in-class.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-class-in-function.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-class.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-comments.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-enum.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-function.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-method.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-namespace.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-struct.cpp
>      clang-tools-extra/trunk/test/clang-doc/mapper-union.cpp
> Modified:
>      clang-tools-extra/trunk/CMakeLists.txt
>      clang-tools-extra/trunk/test/CMakeLists.txt
> 
> Modified: clang-tools-extra/trunk/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/CMakeLists.txt?rev=328270&r1=328269&r2=328270&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/CMakeLists.txt (original)
> +++ clang-tools-extra/trunk/CMakeLists.txt Thu Mar 22 16:34:46 2018
> @@ -7,6 +7,7 @@ add_subdirectory(clang-tidy-vs)
>   endif()
>   
>   add_subdirectory(change-namespace)
> +add_subdirectory(clang-doc)
>   add_subdirectory(clang-query)
>   add_subdirectory(clang-move)
>   add_subdirectory(clangd)
> 
> Added: clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp (added)
> +++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,510 @@
> +//===--  BitcodeWriter.cpp - ClangDoc Bitcode Writer ------------*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "BitcodeWriter.h"
> +#include "llvm/ADT/IndexedMap.h"
> +#include <initializer_list>
> +
> +namespace clang {
> +namespace doc {
> +
> +// Since id enums are not zero-indexed, we need to transform the given id into
> +// its associated index.
> +struct BlockIdToIndexFunctor {
> +  using argument_type = unsigned;
> +  unsigned operator()(unsigned ID) const { return ID - BI_FIRST; }
> +};
> +
> +struct RecordIdToIndexFunctor {
> +  using argument_type = unsigned;
> +  unsigned operator()(unsigned ID) const { return ID - RI_FIRST; }
> +};
> +
> +using AbbrevDsc = void (*)(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev);
> +
> +static void AbbrevGen(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev,
> +                      const std::initializer_list<llvm::BitCodeAbbrevOp> Ops) {
> +  for (const auto &Op : Ops)
> +    Abbrev->Add(Op);
> +}
> +
> +static void BoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
> +  AbbrevGen(Abbrev,
> +            {// 0. Boolean
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
> +                                   BitCodeConstants::BoolSize)});
> +}
> +
> +static void IntAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
> +  AbbrevGen(Abbrev,
> +            {// 0. Fixed-size integer
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
> +                                   BitCodeConstants::IntSize)});
> +}
> +
> +static void SymbolIDAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
> +  AbbrevGen(Abbrev,
> +            {// 0. Fixed-size integer (length of the sha1'd USR)
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
> +                                   BitCodeConstants::USRLengthSize),
> +             // 1. Fixed-size array of Char6 (USR)
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array),
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
> +                                   BitCodeConstants::USRBitLengthSize)});
> +}
> +
> +static void StringAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
> +  AbbrevGen(Abbrev,
> +            {// 0. Fixed-size integer (length of the following string)
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
> +                                   BitCodeConstants::StringLengthSize),
> +             // 1. The string blob
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
> +}
> +
> +// Assumes that the file will not have more than 65535 lines.
> +static void LocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
> +  AbbrevGen(
> +      Abbrev,
> +      {// 0. Fixed-size integer (line number)
> +       llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
> +                             BitCodeConstants::LineNumberSize),
> +       // 1. Fixed-size integer (length of the following string (filename))
> +       llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
> +                             BitCodeConstants::StringLengthSize),
> +       // 2. The string blob
> +       llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
> +}
> +
> +static void ReferenceAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
> +  AbbrevGen(Abbrev,
> +            {// 0. Fixed-size integer (ref type)
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
> +                                   BitCodeConstants::ReferenceTypeSize),
> +             // 1. Fixed-size integer (length of the USR or UnresolvedName)
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
> +                                   BitCodeConstants::StringLengthSize),
> +             // 2. The string blob
> +             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
> +}
> +
> +struct RecordIdDsc {
> +  llvm::StringRef Name;
> +  AbbrevDsc Abbrev = nullptr;
> +
> +  RecordIdDsc() = default;
> +  RecordIdDsc(llvm::StringRef Name, AbbrevDsc Abbrev)
> +      : Name(Name), Abbrev(Abbrev) {}
> +
> +  // Is this 'description' valid?
> +  operator bool() const {
> +    return Abbrev != nullptr && Name.data() != nullptr && !Name.empty();
> +  }
> +};
> +
> +static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
> +    BlockIdNameMap = []() {
> +      llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap;
> +      BlockIdNameMap.resize(BlockIdCount);
> +
> +      // There is no init-list constructor for the IndexedMap, so have to
> +      // improvise
> +      static const std::vector<std::pair<BlockId, const char *const>> Inits = {
> +          {BI_VERSION_BLOCK_ID, "VersionBlock"},
> +          {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"},
> +          {BI_ENUM_BLOCK_ID, "EnumBlock"},
> +          {BI_TYPE_BLOCK_ID, "TypeBlock"},
> +          {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
> +          {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
> +          {BI_RECORD_BLOCK_ID, "RecordBlock"},
> +          {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
> +          {BI_COMMENT_BLOCK_ID, "CommentBlock"}};
> +      assert(Inits.size() == BlockIdCount);
> +      for (const auto &Init : Inits)
> +        BlockIdNameMap[Init.first] = Init.second;
> +      assert(BlockIdNameMap.size() == BlockIdCount);
> +      return BlockIdNameMap;
> +    }();
> +
> +static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
> +    RecordIdNameMap = []() {
> +      llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;
> +      RecordIdNameMap.resize(RecordIdCount);
> +
> +      // There is no init-list constructor for the IndexedMap, so have to
> +      // improvise
> +      static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = {
> +          {VERSION, {"Version", &IntAbbrev}},
> +          {COMMENT_KIND, {"Kind", &StringAbbrev}},
> +          {COMMENT_TEXT, {"Text", &StringAbbrev}},
> +          {COMMENT_NAME, {"Name", &StringAbbrev}},
> +          {COMMENT_DIRECTION, {"Direction", &StringAbbrev}},
> +          {COMMENT_PARAMNAME, {"ParamName", &StringAbbrev}},
> +          {COMMENT_CLOSENAME, {"CloseName", &StringAbbrev}},
> +          {COMMENT_SELFCLOSING, {"SelfClosing", &BoolAbbrev}},
> +          {COMMENT_EXPLICIT, {"Explicit", &BoolAbbrev}},
> +          {COMMENT_ATTRKEY, {"AttrKey", &StringAbbrev}},
> +          {COMMENT_ATTRVAL, {"AttrVal", &StringAbbrev}},
> +          {COMMENT_ARG, {"Arg", &StringAbbrev}},
> +          {TYPE_REF, {"Type", &ReferenceAbbrev}},
> +          {FIELD_TYPE_REF, {"Type", &ReferenceAbbrev}},
> +          {FIELD_TYPE_NAME, {"Name", &StringAbbrev}},
> +          {MEMBER_TYPE_REF, {"Type", &ReferenceAbbrev}},
> +          {MEMBER_TYPE_NAME, {"Name", &StringAbbrev}},
> +          {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
> +          {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
> +          {NAMESPACE_NAME, {"Name", &StringAbbrev}},
> +          {NAMESPACE_NAMESPACE, {"Namespace", &ReferenceAbbrev}},
> +          {ENUM_USR, {"USR", &SymbolIDAbbrev}},
> +          {ENUM_NAME, {"Name", &StringAbbrev}},
> +          {ENUM_NAMESPACE, {"Namespace", &ReferenceAbbrev}},
> +          {ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
> +          {ENUM_LOCATION, {"Location", &LocationAbbrev}},
> +          {ENUM_MEMBER, {"Member", &StringAbbrev}},
> +          {ENUM_SCOPED, {"Scoped", &BoolAbbrev}},
> +          {RECORD_USR, {"USR", &SymbolIDAbbrev}},
> +          {RECORD_NAME, {"Name", &StringAbbrev}},
> +          {RECORD_NAMESPACE, {"Namespace", &ReferenceAbbrev}},
> +          {RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
> +          {RECORD_LOCATION, {"Location", &LocationAbbrev}},
> +          {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
> +          {RECORD_PARENT, {"Parent", &ReferenceAbbrev}},
> +          {RECORD_VPARENT, {"VParent", &ReferenceAbbrev}},
> +          {FUNCTION_USR, {"USR", &SymbolIDAbbrev}},
> +          {FUNCTION_NAME, {"Name", &StringAbbrev}},
> +          {FUNCTION_NAMESPACE, {"Namespace", &ReferenceAbbrev}},
> +          {FUNCTION_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
> +          {FUNCTION_LOCATION, {"Location", &LocationAbbrev}},
> +          {FUNCTION_PARENT, {"Parent", &ReferenceAbbrev}},
> +          {FUNCTION_ACCESS, {"Access", &IntAbbrev}},
> +          {FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}}};
> +      assert(Inits.size() == RecordIdCount);
> +      for (const auto &Init : Inits) {
> +        RecordIdNameMap[Init.first] = Init.second;
> +        assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize);
> +      }
> +      assert(RecordIdNameMap.size() == RecordIdCount);
> +      return RecordIdNameMap;
> +    }();
> +
> +static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
> +    RecordsByBlock{
> +        // Version Block
> +        {BI_VERSION_BLOCK_ID, {VERSION}},
> +        // Comment Block
> +        {BI_COMMENT_BLOCK_ID,
> +         {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION,
> +          COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING,
> +          COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}},
> +        // Type Block
> +        {BI_TYPE_BLOCK_ID, {TYPE_REF}},
> +        // FieldType Block
> +        {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_REF, FIELD_TYPE_NAME}},
> +        // MemberType Block
> +        {BI_MEMBER_TYPE_BLOCK_ID,
> +         {MEMBER_TYPE_REF, MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}},
> +        // Enum Block
> +        {BI_ENUM_BLOCK_ID,
> +         {ENUM_USR, ENUM_NAME, ENUM_NAMESPACE, ENUM_DEFLOCATION, ENUM_LOCATION,
> +          ENUM_MEMBER, ENUM_SCOPED}},
> +        // Namespace Block
> +        {BI_NAMESPACE_BLOCK_ID,
> +         {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_NAMESPACE}},
> +        // Record Block
> +        {BI_RECORD_BLOCK_ID,
> +         {RECORD_USR, RECORD_NAME, RECORD_NAMESPACE, RECORD_DEFLOCATION,
> +          RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_PARENT, RECORD_VPARENT}},
> +        // Function Block
> +        {BI_FUNCTION_BLOCK_ID,
> +         {FUNCTION_USR, FUNCTION_NAME, FUNCTION_NAMESPACE, FUNCTION_DEFLOCATION,
> +          FUNCTION_LOCATION, FUNCTION_PARENT, FUNCTION_ACCESS,
> +          FUNCTION_IS_METHOD}}};
> +
> +// AbbreviationMap
> +
> +void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,
> +                                                 unsigned AbbrevID) {
> +  assert(RecordIdNameMap[RID] && "Unknown RecordId.");
> +  assert(Abbrevs.find(RID) == Abbrevs.end() && "Abbreviation already added.");
> +  Abbrevs[RID] = AbbrevID;
> +}
> +
> +unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {
> +  assert(RecordIdNameMap[RID] && "Unknown RecordId.");
> +  assert(Abbrevs.find(RID) != Abbrevs.end() && "Unknown abbreviation.");
> +  return Abbrevs.lookup(RID);
> +}
> +
> +// Validation and Overview Blocks
> +
> +/// \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"))
> +    Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize);
> +}
> +
> +void ClangDocBitcodeWriter::emitVersionBlock() {
> +  StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);
> +  emitRecord(VersionNumber, VERSION);
> +}
> +
> +/// \brief Emits a block ID and the block name to the BLOCKINFO block.
> +void ClangDocBitcodeWriter::emitBlockID(BlockId BID) {
> +  const auto &BlockIdName = BlockIdNameMap[BID];
> +  assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId."); > +
> +  Record.clear();
> +  Record.push_back(BID);
> +  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
> +  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
> +                    ArrayRef<unsigned char>(BlockIdNameMap[BID].bytes_begin(),
> +                                            BlockIdNameMap[BID].bytes_end()));
> +}
> +
> +/// \brief Emits a record name to the BLOCKINFO block.
> +void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {
> +  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
> +  prepRecordData(ID);
> +  Record.append(RecordIdNameMap[ID].Name.begin(),
> +                RecordIdNameMap[ID].Name.end());
> +  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
> +}
> +
> +// Abbreviations
> +
> +void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {
> +  assert(RecordIdNameMap[ID] && "Unknown abbreviation.");
> +  auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
> +  Abbrev->Add(llvm::BitCodeAbbrevOp(ID));
> +  RecordIdNameMap[ID].Abbrev(Abbrev);
> +  Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, std::move(Abbrev)));
> +}
> +
> +// Records
> +
> +void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) {
> +  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
> +  assert(RecordIdNameMap[ID].Abbrev == &SymbolIDAbbrev &&
> +         "Abbrev type mismatch.");
> +  if (!prepRecordData(ID, !Sym.empty()))
> +    return;
> +  assert(Sym.size() == 20);
> +  Record.push_back(Sym.size());
> +  Record.append(Sym.begin(), Sym.end());
> +  Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
> +}
> +
> +void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) {
> +  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
> +  assert(RecordIdNameMap[ID].Abbrev == &StringAbbrev &&
> +         "Abbrev type mismatch.");
> +  if (!prepRecordData(ID, !Str.empty()))
> +    return;
> +  assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));
> +  Record.push_back(Str.size());
> +  Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str);
> +}
> +
> +void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
> +  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
> +  assert(RecordIdNameMap[ID].Abbrev == &LocationAbbrev &&
> +         "Abbrev type mismatch.");
> +  if (!prepRecordData(ID, true))
> +    return;
> +  // FIXME: Assert that the line number is of the appropriate size.
> +  Record.push_back(Loc.LineNumber);
> +  assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
> +  // Record.push_back(Loc.Filename.size());
> +  // Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);
> +  Record.push_back(4);
> +  Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, "test");
> +}
> +
> +void ClangDocBitcodeWriter::emitRecord(const Reference &Ref, RecordId ID) {
> +  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
> +  assert(RecordIdNameMap[ID].Abbrev == &ReferenceAbbrev &&
> +         "Abbrev type mismatch.");
> +  SmallString<40> StringUSR;
> +  StringRef OutString;
> +  if (Ref.RefType == InfoType::IT_default)
> +    OutString = Ref.UnresolvedName;
> +  else {
> +    StringUSR = llvm::toHex(llvm::toStringRef(Ref.USR));
> +    OutString = StringUSR;
> +  }
> +  if (!prepRecordData(ID, !OutString.empty()))
> +    return;
> +  assert(OutString.size() < (1U << BitCodeConstants::StringLengthSize));
> +  Record.push_back((int)Ref.RefType);
> +  Record.push_back(OutString.size());
> +  Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, OutString);
> +}
> +
> +void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {
> +  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
> +  assert(RecordIdNameMap[ID].Abbrev == &BoolAbbrev && "Abbrev type mismatch.");
> +  if (!prepRecordData(ID, Val))
> +    return;
> +  Record.push_back(Val);
> +  Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
> +}
> +
> +void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) {
> +  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
> +  assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
> +  if (!prepRecordData(ID, Val))
> +    return;
> +  // FIXME: Assert that the integer is of the appropriate size.
> +  Record.push_back(Val);
> +  Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
> +}
> +
> +void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) {
> +  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
> +  assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
> +  if (!prepRecordData(ID, Val))
> +    return;
> +  assert(Val < (1U << BitCodeConstants::IntSize));
> +  Record.push_back(Val);
> +  Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
> +}
> +
> +bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {
> +  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
> +  if (!ShouldEmit)
> +    return false;
> +  Record.clear();
> +  Record.push_back(ID);
> +  return true;
> +}
> +
> +// BlockInfo Block
> +
> +void ClangDocBitcodeWriter::emitBlockInfoBlock() {
> +  Stream.EnterBlockInfoBlock();
> +  for (const auto &Block : RecordsByBlock) {
> +    assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));
> +    emitBlockInfo(Block.first, Block.second);
> +  }
> +  Stream.ExitBlock();
> +}
> +
> +void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID,
> +                                          const std::vector<RecordId> &RIDs) {
> +  assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize));
> +  emitBlockID(BID);
> +  for (RecordId RID : RIDs) {
> +    emitRecordID(RID);
> +    emitAbbrev(RID, BID);
> +  }
> +}
> +
> +// Block emission
> +
> +void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
> +  StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
> +  emitRecord(T.Type, TYPE_REF);
> +}
> +
> +void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
> +  StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
> +  emitRecord(T.Type, FIELD_TYPE_REF);
> +  emitRecord(T.Name, FIELD_TYPE_NAME);
> +}
> +
> +void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
> +  StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
> +  emitRecord(T.Type, MEMBER_TYPE_REF);
> +  emitRecord(T.Name, MEMBER_TYPE_NAME);
> +  emitRecord(T.Access, MEMBER_TYPE_ACCESS);
> +}
> +
> +void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
> +  StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
> +  for (const auto &L :
> +       std::vector<std::pair<llvm::StringRef, RecordId>>{
> +           {I.Kind, COMMENT_KIND},
> +           {I.Text, COMMENT_TEXT},
> +           {I.Name, COMMENT_NAME},
> +           {I.Direction, COMMENT_DIRECTION},
> +           {I.ParamName, COMMENT_PARAMNAME},
> +           {I.CloseName, COMMENT_CLOSENAME}})
> +    emitRecord(L.first, L.second);
> +  emitRecord(I.SelfClosing, COMMENT_SELFCLOSING);
> +  emitRecord(I.Explicit, COMMENT_EXPLICIT);
> +  for (const auto &A : I.AttrKeys)
> +    emitRecord(A, COMMENT_ATTRKEY);
> +  for (const auto &A : I.AttrValues)
> +    emitRecord(A, COMMENT_ATTRVAL);
> +  for (const auto &A : I.Args)
> +    emitRecord(A, COMMENT_ARG);
> +  for (const auto &C : I.Children)
> +    emitBlock(*C);
> +}
> +
> +#define EMITINFO(X)                                                            \
> +  emitRecord(I.USR, X##_USR);                                                  \
> +  emitRecord(I.Name, X##_NAME);                                                \
> +  for (const auto &N : I.Namespace)                                            \
> +    emitRecord(N, X##_NAMESPACE);                                              \
> +  for (const auto &CI : I.Description)                                         \
> +    emitBlock(CI);
> +
> +void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
> +  StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
> +  EMITINFO(NAMESPACE)
> +}
> +
> +void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
> +  StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
> +  EMITINFO(ENUM)
> +  if (I.DefLoc)
> +    emitRecord(I.DefLoc.getValue(), ENUM_DEFLOCATION);
> +  for (const auto &L : I.Loc)
> +    emitRecord(L, ENUM_LOCATION);
> +  emitRecord(I.Scoped, ENUM_SCOPED);
> +  for (const auto &N : I.Members)
> +    emitRecord(N, ENUM_MEMBER);
> +}
> +
> +void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
> +  StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
> +  EMITINFO(RECORD)
> +  if (I.DefLoc)
> +    emitRecord(I.DefLoc.getValue(), RECORD_DEFLOCATION);
> +  for (const auto &L : I.Loc)
> +    emitRecord(L, RECORD_LOCATION);
> +  emitRecord(I.TagType, RECORD_TAG_TYPE);
> +  for (const auto &N : I.Members)
> +    emitBlock(N);
> +  for (const auto &P : I.Parents)
> +    emitRecord(P, RECORD_PARENT);
> +  for (const auto &P : I.VirtualParents)
> +    emitRecord(P, RECORD_VPARENT);
> +}
> +
> +void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
> +  StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
> +  EMITINFO(FUNCTION)
> +  emitRecord(I.IsMethod, FUNCTION_IS_METHOD);
> +  if (I.DefLoc)
> +    emitRecord(I.DefLoc.getValue(), FUNCTION_DEFLOCATION);
> +  for (const auto &L : I.Loc)
> +    emitRecord(L, FUNCTION_LOCATION);
> +  emitRecord(I.Parent, FUNCTION_PARENT);
> +  emitBlock(I.ReturnType);
> +  for (const auto &N : I.Params)
> +    emitBlock(N);
> +}
> +
> +#undef EMITINFO
> +
> +} // namespace doc
> +} // namespace clang
> 
> Added: clang-tools-extra/trunk/clang-doc/BitcodeWriter.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.h?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/BitcodeWriter.h (added)
> +++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.h Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,201 @@
> +//===--  BitcodeWriter.h - ClangDoc Bitcode Writer --------------*- 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 writer for serializing the clang-doc internal
> +// representation to LLVM bitcode. The writer takes in a stream and emits the
> +// generated bitcode to that stream.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
> +
> +#include "Representation.h"
> +#include "clang/AST/AST.h"
> +#include "llvm/ADT/DenseMap.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Bitcode/BitstreamWriter.h"
> +#include <initializer_list>
> +#include <vector>
> +
> +namespace clang {
> +namespace doc {
> +
> +// Current version number of clang-doc bitcode.
> +// Should be bumped when removing or changing BlockIds, RecordIds, or
> +// BitCodeConstants, though they can be added without breaking it.
> +static const unsigned VersionNumber = 1;
> +
> +struct BitCodeConstants {
> +  static constexpr unsigned RecordSize = 16U;
> +  static constexpr unsigned SignatureBitSize = 8U;
> +  static constexpr unsigned SubblockIDSize = 4U;
> +  static constexpr unsigned BoolSize = 1U;
> +  static constexpr unsigned IntSize = 16U;
> +  static constexpr unsigned StringLengthSize = 16U;
> +  static constexpr unsigned FilenameLengthSize = 16U;
> +  static constexpr unsigned LineNumberSize = 16U;
> +  static constexpr unsigned ReferenceTypeSize = 8U;
> +  static constexpr unsigned USRLengthSize = 6U;
> +  static constexpr unsigned USRBitLengthSize = 8U;
> +};
> +
> +// New Ids need to be added to both the enum here and the relevant IdNameMap in
> +// the implementation file.
> +enum BlockId {
> +  BI_VERSION_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
> +  BI_NAMESPACE_BLOCK_ID,
> +  BI_ENUM_BLOCK_ID,
> +  BI_TYPE_BLOCK_ID,
> +  BI_FIELD_TYPE_BLOCK_ID,
> +  BI_MEMBER_TYPE_BLOCK_ID,
> +  BI_RECORD_BLOCK_ID,
> +  BI_FUNCTION_BLOCK_ID,
> +  BI_COMMENT_BLOCK_ID,
> +  BI_FIRST = BI_VERSION_BLOCK_ID,
> +  BI_LAST = BI_COMMENT_BLOCK_ID
> +};
> +
> +// New Ids need to be added to the enum here, and to the relevant IdNameMap and
> +// initialization list in the implementation file.
> +#define INFORECORDS(X) X##_USR, X##_NAME, X##_NAMESPACE
> +
> +enum RecordId {
> +  VERSION = 1,
> +  INFORECORDS(FUNCTION),
> +  FUNCTION_DEFLOCATION,
> +  FUNCTION_LOCATION,
> +  FUNCTION_PARENT,
> +  FUNCTION_ACCESS,
> +  FUNCTION_IS_METHOD,
> +  COMMENT_KIND,
> +  COMMENT_TEXT,
> +  COMMENT_NAME,
> +  COMMENT_DIRECTION,
> +  COMMENT_PARAMNAME,
> +  COMMENT_CLOSENAME,
> +  COMMENT_SELFCLOSING,
> +  COMMENT_EXPLICIT,
> +  COMMENT_ATTRKEY,
> +  COMMENT_ATTRVAL,
> +  COMMENT_ARG,
> +  TYPE_REF,
> +  FIELD_TYPE_REF,
> +  FIELD_TYPE_NAME,
> +  MEMBER_TYPE_REF,
> +  MEMBER_TYPE_NAME,
> +  MEMBER_TYPE_ACCESS,
> +  INFORECORDS(NAMESPACE),
> +  INFORECORDS(ENUM),
> +  ENUM_DEFLOCATION,
> +  ENUM_LOCATION,
> +  ENUM_MEMBER,
> +  ENUM_SCOPED,
> +  INFORECORDS(RECORD),
> +  RECORD_DEFLOCATION,
> +  RECORD_LOCATION,
> +  RECORD_TAG_TYPE,
> +  RECORD_PARENT,
> +  RECORD_VPARENT,
> +  RI_FIRST = VERSION,
> +  RI_LAST = RECORD_VPARENT
> +};
> +
> +static constexpr unsigned BlockIdCount = BI_LAST - BI_FIRST + 1;
> +static constexpr unsigned RecordIdCount = RI_LAST - RI_FIRST + 1;
> +
> +#undef INFORECORDS
> +
> +class ClangDocBitcodeWriter {
> +public:
> +  ClangDocBitcodeWriter(llvm::BitstreamWriter &Stream) : Stream(Stream) {
> +    emitHeader();
> +    emitBlockInfoBlock();
> +    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
> +
> +  // Block emission of different info types.
> +  void emitBlock(const NamespaceInfo &I);
> +  void emitBlock(const RecordInfo &I);
> +  void emitBlock(const FunctionInfo &I);
> +  void emitBlock(const EnumInfo &I);
> +  void emitBlock(const TypeInfo &B);
> +  void emitBlock(const FieldTypeInfo &B);
> +  void emitBlock(const MemberTypeInfo &B);
> +  void emitBlock(const CommentInfo &B);
> +
> +private:
> +  class AbbreviationMap {
> +    llvm::DenseMap<unsigned, unsigned> Abbrevs;
> +
> +  public:
> +    AbbreviationMap() : Abbrevs(RecordIdCount) {}
> +
> +    void add(RecordId RID, unsigned AbbrevID);
> +    unsigned get(RecordId RID) const;
> +  };
> +
> +  class StreamSubBlockGuard {
> +    llvm::BitstreamWriter &Stream;
> +
> +  public:
> +    StreamSubBlockGuard(llvm::BitstreamWriter &Stream_, BlockId ID)
> +        : Stream(Stream_) {
> +      // NOTE: SubBlockIDSize could theoretically be calculated on the fly,
> +      // based on the initialization list of records in each block.
> +      Stream.EnterSubblock(ID, BitCodeConstants::SubblockIDSize);
> +    }
> +
> +    StreamSubBlockGuard() = default;
> +    StreamSubBlockGuard(const StreamSubBlockGuard &) = delete;
> +    StreamSubBlockGuard &operator=(const StreamSubBlockGuard &) = delete;
> +
> +    ~StreamSubBlockGuard() { Stream.ExitBlock(); }
> +  };
> +
> +  // Emission of validation and overview blocks.
> +  void emitHeader();
> +  void emitVersionBlock();
> +  void emitRecordID(RecordId ID);
> +  void emitBlockID(BlockId ID);
> +  void emitBlockInfoBlock();
> +  void emitBlockInfo(BlockId BID, const std::vector<RecordId> &RIDs);
> +
> +  // Emission of individual record types.
> +  void emitRecord(StringRef Str, RecordId ID);
> +  void emitRecord(const SymbolID &Str, RecordId ID);
> +  void emitRecord(const Location &Loc, RecordId ID);
> +  void emitRecord(const Reference &Ref, RecordId ID);
> +  void emitRecord(bool Value, RecordId ID);
> +  void emitRecord(int Value, RecordId ID);
> +  void emitRecord(unsigned Value, RecordId ID);
> +  bool prepRecordData(RecordId ID, bool ShouldEmit = true);
> +
> +  // Emission of appropriate abbreviation type.
> +  void emitAbbrev(RecordId ID, BlockId Block);
> +
> +  // Static size is the maximum length of the block/record names we're pushing
> +  // to this + 1. Longest is currently `MemberTypeBlock` at 15 chars.
> +  SmallVector<uint32_t, BitCodeConstants::RecordSize> Record;
> +  llvm::BitstreamWriter &Stream;
> +  AbbreviationMap Abbrevs;
> +};
> +
> +} // namespace doc
> +} // namespace clang
> +
> +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
> 
> Added: clang-tools-extra/trunk/clang-doc/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/CMakeLists.txt?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/CMakeLists.txt (added)
> +++ clang-tools-extra/trunk/clang-doc/CMakeLists.txt Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,23 @@
> +set(LLVM_LINK_COMPONENTS
> +  support
> +  )
> +
> +add_clang_library(clangDoc
> +  BitcodeWriter.cpp
> +  ClangDoc.cpp
> +  Mapper.cpp
> +  Serialize.cpp
> +
> +  LINK_LIBS
> +  clangAnalysis
> +  clangAST
> +  clangASTMatchers
> +  clangBasic
> +  clangFrontend
> +  clangIndex
> +  clangLex
> +  clangTooling
> +  clangToolingCore
> +  )
> +
> +add_subdirectory(tool)
> 
> Added: clang-tools-extra/trunk/clang-doc/ClangDoc.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/ClangDoc.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/ClangDoc.cpp (added)
> +++ clang-tools-extra/trunk/clang-doc/ClangDoc.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,61 @@
> +//===-- ClangDoc.cpp - ClangDoc ---------------------------------*- 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 the main entry point for the clang-doc tool. It runs
> +// the clang-doc mapper on a given set of source code files using a
> +// FrontendActionFactory.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "ClangDoc.h"
> +#include "Mapper.h"
> +#include "clang/AST/AST.h"
> +#include "clang/AST/ASTConsumer.h"
> +#include "clang/AST/ASTContext.h"
> +#include "clang/AST/RecursiveASTVisitor.h"
> +#include "clang/Frontend/ASTConsumers.h"
> +#include "clang/Frontend/CompilerInstance.h"
> +#include "clang/Frontend/FrontendActions.h"
> +
> +namespace clang {
> +namespace doc {
> +
> +class MapperActionFactory : public tooling::FrontendActionFactory {
> +public:
> +  MapperActionFactory(tooling::ExecutionContext *ECtx) : ECtx(ECtx) {}
> +  clang::FrontendAction *create() override;
> +
> +private:
> +  tooling::ExecutionContext *ECtx;
> +};
> +
> +clang::FrontendAction *MapperActionFactory::create() {
> +  class ClangDocAction : public clang::ASTFrontendAction {
> +  public:
> +    ClangDocAction(ExecutionContext *ECtx) : ECtx(ECtx) {}
> +
> +    std::unique_ptr<clang::ASTConsumer>
> +    CreateASTConsumer(clang::CompilerInstance &Compiler,
> +                      llvm::StringRef InFile) override {
> +      return llvm::make_unique<MapASTVisitor>(&Compiler.getASTContext(), ECtx);
> +    }
> +
> +  private:
> +    ExecutionContext *ECtx;
> +  };
> +  return new ClangDocAction(ECtx);
> +}
> +
> +std::unique_ptr<tooling::FrontendActionFactory>
> +newMapperActionFactory(tooling::ExecutionContext *ECtx) {
> +  return llvm::make_unique<MapperActionFactory>(ECtx);
> +}
> +
> +} // namespace doc
> +} // namespace clang
> 
> Added: clang-tools-extra/trunk/clang-doc/ClangDoc.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/ClangDoc.h?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/ClangDoc.h (added)
> +++ clang-tools-extra/trunk/clang-doc/ClangDoc.h Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,33 @@
> +//===-- ClangDoc.h - ClangDoc -----------------------------------*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file exposes a method to craete the FrontendActionFactory for the
> +// clang-doc tool. The factory runs the clang-doc mapper on a given set of
> +// source code files, storing the results key-value pairs in its
> +// ExecutionContext.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
> +
> +#include "clang/Tooling/Execution.h"
> +#include "clang/Tooling/StandaloneExecution.h"
> +#include "clang/Tooling/Tooling.h"
> +
> +namespace clang {
> +namespace doc {
> +
> +std::unique_ptr<tooling::FrontendActionFactory>
> +newMapperActionFactory(tooling::ExecutionContext *ECtx);
> +
> +} // namespace doc
> +} // namespace clang
> +
> +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
> 
> Added: clang-tools-extra/trunk/clang-doc/Mapper.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Mapper.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/Mapper.cpp (added)
> +++ clang-tools-extra/trunk/clang-doc/Mapper.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,86 @@
> +//===-- Mapper.cpp - ClangDoc Mapper ----------------------------*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "Mapper.h"
> +#include "BitcodeWriter.h"
> +#include "Serialize.h"
> +#include "clang/AST/Comment.h"
> +#include "clang/Index/USRGeneration.h"
> +#include "llvm/ADT/StringExtras.h"
> +
> +using clang::comments::FullComment;
> +
> +namespace clang {
> +namespace doc {
> +
> +void MapASTVisitor::HandleTranslationUnit(ASTContext &Context) {
> +  TraverseDecl(Context.getTranslationUnitDecl());
> +}
> +
> +template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
> +  // If we're looking a decl not in user files, skip this decl.
> +  if (D->getASTContext().getSourceManager().isInSystemHeader(D->getLocation()))
> +    return true;
> +
> +  llvm::SmallString<128> USR;
> +  // If there is an error generating a USR for the decl, skip this decl.
> +  if (index::generateUSRForDecl(D, USR))
> +    return true;
> +
> +  ECtx->reportResult(llvm::toHex(llvm::toStringRef(serialize::hashUSR(USR))),
> +                     serialize::emitInfo(D, getComment(D, D->getASTContext()),
> +                                         getLine(D, D->getASTContext()),
> +                                         getFile(D, D->getASTContext())));
> +  return true;
> +}
> +
> +bool MapASTVisitor::VisitNamespaceDecl(const NamespaceDecl *D) {
> +  return mapDecl(D);
> +}
> +
> +bool MapASTVisitor::VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
> +
> +bool MapASTVisitor::VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
> +
> +bool MapASTVisitor::VisitCXXMethodDecl(const CXXMethodDecl *D) {
> +  return mapDecl(D);
> +}
> +
> +bool MapASTVisitor::VisitFunctionDecl(const FunctionDecl *D) {
> +  // Don't visit CXXMethodDecls twice
> +  if (dyn_cast<CXXMethodDecl>(D))
> +    return true;
> +  return mapDecl(D);
> +}
> +
> +comments::FullComment *
> +MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const {
> +  RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
> +  // FIXME: Move setAttached to the initial comment parsing.
> +  if (Comment) {
> +    Comment->setAttached();
> +    return Comment->parse(Context, nullptr, D);
> +  }
> +  return nullptr;
> +}
> +
> +int MapASTVisitor::getLine(const NamedDecl *D,
> +                           const ASTContext &Context) const {
> +  return Context.getSourceManager().getPresumedLoc(D->getLocStart()).getLine();
> +}
> +
> +llvm::StringRef MapASTVisitor::getFile(const NamedDecl *D,
> +                                       const ASTContext &Context) const {
> +  return Context.getSourceManager()
> +      .getPresumedLoc(D->getLocStart())
> +      .getFilename();
> +}
> +
> +} // namespace doc
> +} // namespace clang
> 
> Added: clang-tools-extra/trunk/clang-doc/Mapper.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Mapper.h?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/Mapper.h (added)
> +++ clang-tools-extra/trunk/clang-doc/Mapper.h Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,57 @@
> +//===-- Mapper.h - ClangDoc Mapper ------------------------------*- 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 the Mapper piece of the clang-doc tool. It implements
> +// a RecursiveASTVisitor to look at each declaration and populate the info
> +// into the internal representation. Each seen declaration is serialized to
> +// to bitcode and written out to the ExecutionContext as a KV pair where the
> +// key is the declaration's USR and the value is the serialized bitcode.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_MAPPER_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_MAPPER_H
> +
> +#include "clang/AST/RecursiveASTVisitor.h"
> +#include "clang/Tooling/Execution.h"
> +
> +using namespace clang::comments;
> +using namespace clang::tooling;
> +
> +namespace clang {
> +namespace doc {
> +
> +class MapASTVisitor : public clang::RecursiveASTVisitor<MapASTVisitor>,
> +                      public ASTConsumer {
> +public:
> +  explicit MapASTVisitor(ASTContext *Ctx, ExecutionContext *ECtx)
> +      : ECtx(ECtx) {}
> +
> +  void HandleTranslationUnit(ASTContext &Context) override;
> +  bool VisitNamespaceDecl(const NamespaceDecl *D);
> +  bool VisitRecordDecl(const RecordDecl *D);
> +  bool VisitEnumDecl(const EnumDecl *D);
> +  bool VisitCXXMethodDecl(const CXXMethodDecl *D);
> +  bool VisitFunctionDecl(const FunctionDecl *D);
> +
> +private:
> +  template <typename T> bool mapDecl(const T *D);
> +
> +  int getLine(const NamedDecl *D, const ASTContext &Context) const;
> +  StringRef getFile(const NamedDecl *D, const ASTContext &Context) const;
> +  comments::FullComment *getComment(const NamedDecl *D,
> +                                    const ASTContext &Context) const;
> +
> +  ExecutionContext *ECtx;
> +};
> +
> +} // namespace doc
> +} // namespace clang
> +
> +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_MAPPER_H
> 
> Added: clang-tools-extra/trunk/clang-doc/Representation.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.h?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/Representation.h (added)
> +++ clang-tools-extra/trunk/clang-doc/Representation.h Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,184 @@
> +///===-- Representation.h - ClangDoc Represenation --------------*- 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 internal representations of different declaration
> +// types for the clang-doc tool.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
> +
> +#include "clang/AST/Type.h"
> +#include "clang/Basic/Specifiers.h"
> +#include "llvm/ADT/Optional.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/ADT/StringExtras.h"
> +#include <array>
> +#include <string>
> +
> +namespace clang {
> +namespace doc {
> +
> +using SymbolID = std::array<uint8_t, 20>;
> +
> +struct Info;
> +enum class InfoType {
> +  IT_namespace,
> +  IT_record,
> +  IT_function,
> +  IT_enum,
> +  IT_default
> +};
> +
> +// A representation of a parsed comment.
> +struct CommentInfo {
> +  CommentInfo() = default;
> +  CommentInfo(CommentInfo &&Other) : Children(std::move(Other.Children)) {}
> +
> +  SmallString<16>
> +      Kind; // Kind of comment (TextComment, InlineCommandComment,
> +            // HTMLStartTagComment, HTMLEndTagComment, BlockCommandComment,
> +            // ParamCommandComment, TParamCommandComment, VerbatimBlockComment,
> +            // VerbatimBlockLineComment, VerbatimLineComment).
> +  SmallString<64> Text;      // Text of the comment.
> +  SmallString<16> Name;      // Name of the comment (for Verbatim and HTML).
> +  SmallString<8> Direction;  // Parameter direction (for (T)ParamCommand).
> +  SmallString<16> ParamName; // Parameter name (for (T)ParamCommand).
> +  SmallString<16> CloseName; // Closing tag name (for VerbatimBlock).
> +  bool SelfClosing = false;  // Indicates if tag is self-closing (for HTML).
> +  bool Explicit = false; // Indicates if the direction of a param is explicit
> +                         // (for (T)ParamCommand).
> +  llvm::SmallVector<SmallString<16>, 4>
> +      AttrKeys; // List of attribute keys (for HTML).
> +  llvm::SmallVector<SmallString<16>, 4>
> +      AttrValues; // List of attribute values for each key (for HTML).
> +  llvm::SmallVector<SmallString<16>, 4>
> +      Args; // List of arguments to commands (for InlineCommand).
> +  std::vector<std::unique_ptr<CommentInfo>>
> +      Children; // List of child comments for this CommentInfo.
> +};
> +
> +struct Reference {
> +  Reference() = default;
> +  Reference(llvm::StringRef Name) : UnresolvedName(Name) {}
> +  Reference(SymbolID USR, InfoType IT) : USR(USR), RefType(IT) {}
> +
> +  SymbolID USR;                   // Unique identifer for referenced decl
> +  SmallString<16> UnresolvedName; // Name of unresolved type.
> +  InfoType RefType =
> +      InfoType::IT_default; // Indicates the type of this Reference (namespace,
> +                            // record, function, enum, default).
> +};
> +
> +// A base struct for TypeInfos
> +struct TypeInfo {
> +  TypeInfo() = default;
> +  TypeInfo(SymbolID &Type, InfoType IT) : Type(Type, IT) {}
> +  TypeInfo(llvm::StringRef RefName) : Type(RefName) {}
> +
> +  Reference Type; // Referenced type in this info.
> +};
> +
> +// Info for field types.
> +struct FieldTypeInfo : public TypeInfo {
> +  FieldTypeInfo() = default;
> +  FieldTypeInfo(SymbolID &Type, InfoType IT, llvm::StringRef Name)
> +      : TypeInfo(Type, IT), Name(Name) {}
> +  FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
> +      : TypeInfo(RefName), Name(Name) {}
> +
> +  SmallString<16> Name; // Name associated with this info.
> +};
> +
> +// Info for member types.
> +struct MemberTypeInfo : public FieldTypeInfo {
> +  MemberTypeInfo() = default;
> +  MemberTypeInfo(SymbolID &Type, InfoType IT, llvm::StringRef Name)
> +      : FieldTypeInfo(Type, IT, Name) {}
> +  MemberTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
> +      : FieldTypeInfo(RefName, Name) {}
> +
> +  AccessSpecifier Access =
> +      clang::AccessSpecifier::AS_none; // Access level associated with this
> +                                       // info (public, protected, private,
> +                                       // none).
> +};
> +
> +struct Location {
> +  Location() = default;
> +  Location(int LineNumber, SmallString<16> Filename)
> +      : LineNumber(LineNumber), Filename(std::move(Filename)) {}
> +
> +  int LineNumber;           // Line number of this Location.
> +  SmallString<32> Filename; // File for this 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.
> +  llvm::SmallVector<Reference, 4>
> +      Namespace; // List of parent namespaces for this decl.
> +  std::vector<CommentInfo> Description; // Comment description of this decl.
> +};
> +
> +// Info for namespaces.
> +struct NamespaceInfo : public Info {};
> +
> +// Info for symbols.
> +struct SymbolInfo : public Info {
> +  llvm::Optional<Location> DefLoc;    // Location where this decl is defined.
> +  llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
> +};
> +
> +// TODO: Expand to allow for documenting templating and default args.
> +// Info for functions.
> +struct FunctionInfo : public SymbolInfo {
> +  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.
> +  llvm::SmallVector<FieldTypeInfo, 4> Params; // List of parameters.
> +  AccessSpecifier Access =
> +      AccessSpecifier::AS_none; // Access level for this method (public,
> +                                // private, protected, none).
> +};
> +
> +// TODO: Expand to allow for documenting templating, inheritance access,
> +// friend classes
> +// Info for types.
> +struct RecordInfo : public SymbolInfo {
> +  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>
> +      VirtualParents; // List of virtual base/parent records.
> +};
> +
> +// TODO: Expand to allow for documenting templating.
> +// Info for types.
> +struct EnumInfo : public SymbolInfo {
> +  bool Scoped =
> +      false; // Indicates whether this enum is scoped (e.g. enum class).
> +  llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members.
> +};
> +
> +// TODO: Add functionality to include separate markdown pages.
> +
> +} // namespace doc
> +} // namespace clang
> +
> +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
> 
> Added: clang-tools-extra/trunk/clang-doc/Serialize.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Serialize.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/Serialize.cpp (added)
> +++ clang-tools-extra/trunk/clang-doc/Serialize.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,336 @@
> +//===-- Serializer.cpp - ClangDoc Serializer --------------------*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "Serialize.h"
> +#include "BitcodeWriter.h"
> +#include "clang/AST/Comment.h"
> +#include "clang/Index/USRGeneration.h"
> +#include "llvm/ADT/Hashing.h"
> +#include "llvm/ADT/StringExtras.h"
> +#include "llvm/Support/SHA1.h"
> +
> +using clang::comments::FullComment;
> +
> +namespace clang {
> +namespace doc {
> +namespace serialize {
> +
> +SymbolID hashUSR(llvm::StringRef USR) {
> +  return llvm::SHA1::hash(arrayRefFromStringRef(USR));
> +}
> +
> +class ClangDocCommentVisitor
> +    : public ConstCommentVisitor<ClangDocCommentVisitor> {
> +public:
> +  ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
> +
> +  void parseComment(const comments::Comment *C);
> +
> +  void visitTextComment(const TextComment *C);
> +  void visitInlineCommandComment(const InlineCommandComment *C);
> +  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
> +  void visitHTMLEndTagComment(const HTMLEndTagComment *C);
> +  void visitBlockCommandComment(const BlockCommandComment *C);
> +  void visitParamCommandComment(const ParamCommandComment *C);
> +  void visitTParamCommandComment(const TParamCommandComment *C);
> +  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
> +  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
> +  void visitVerbatimLineComment(const VerbatimLineComment *C);
> +
> +private:
> +  std::string getCommandName(unsigned CommandID) const;
> +  bool isWhitespaceOnly(StringRef S) const;
> +
> +  CommentInfo &CurrentCI;
> +};
> +
> +void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
> +  CurrentCI.Kind = C->getCommentKindName();
> +  ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
> +  for (comments::Comment *Child :
> +       llvm::make_range(C->child_begin(), C->child_end())) {
> +    CurrentCI.Children.emplace_back(llvm::make_unique<CommentInfo>());
> +    ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
> +    Visitor.parseComment(Child);
> +  }
> +}
> +
> +void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
> +  if (!isWhitespaceOnly(C->getText()))
> +    CurrentCI.Text = C->getText();
> +}
> +
> +void ClangDocCommentVisitor::visitInlineCommandComment(
> +    const InlineCommandComment *C) {
> +  CurrentCI.Name = getCommandName(C->getCommandID());
> +  for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
> +    CurrentCI.Args.push_back(C->getArgText(I));
> +}
> +
> +void ClangDocCommentVisitor::visitHTMLStartTagComment(
> +    const HTMLStartTagComment *C) {
> +  CurrentCI.Name = C->getTagName();
> +  CurrentCI.SelfClosing = C->isSelfClosing();
> +  for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
> +    const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
> +    CurrentCI.AttrKeys.push_back(Attr.Name);
> +    CurrentCI.AttrValues.push_back(Attr.Value);
> +  }
> +}
> +
> +void ClangDocCommentVisitor::visitHTMLEndTagComment(
> +    const HTMLEndTagComment *C) {
> +  CurrentCI.Name = C->getTagName();
> +  CurrentCI.SelfClosing = true;
> +}
> +
> +void ClangDocCommentVisitor::visitBlockCommandComment(
> +    const BlockCommandComment *C) {
> +  CurrentCI.Name = getCommandName(C->getCommandID());
> +  for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
> +    CurrentCI.Args.push_back(C->getArgText(I));
> +}
> +
> +void ClangDocCommentVisitor::visitParamCommandComment(
> +    const ParamCommandComment *C) {
> +  CurrentCI.Direction =
> +      ParamCommandComment::getDirectionAsString(C->getDirection());
> +  CurrentCI.Explicit = C->isDirectionExplicit();
> +  if (C->hasParamName())
> +    CurrentCI.ParamName = C->getParamNameAsWritten();
> +}
> +
> +void ClangDocCommentVisitor::visitTParamCommandComment(
> +    const TParamCommandComment *C) {
> +  if (C->hasParamName())
> +    CurrentCI.ParamName = C->getParamNameAsWritten();
> +}
> +
> +void ClangDocCommentVisitor::visitVerbatimBlockComment(
> +    const VerbatimBlockComment *C) {
> +  CurrentCI.Name = getCommandName(C->getCommandID());
> +  CurrentCI.CloseName = C->getCloseName();
> +}
> +
> +void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
> +    const VerbatimBlockLineComment *C) {
> +  if (!isWhitespaceOnly(C->getText()))
> +    CurrentCI.Text = C->getText();
> +}
> +
> +void ClangDocCommentVisitor::visitVerbatimLineComment(
> +    const VerbatimLineComment *C) {
> +  if (!isWhitespaceOnly(C->getText()))
> +    CurrentCI.Text = C->getText();
> +}
> +
> +bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
> +  return std::all_of(S.begin(), S.end(), isspace);
> +}
> +
> +std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
> +  const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
> +  if (Info)
> +    return Info->Name;
> +  // TODO: Add parsing for \file command.
> +  return "<not a builtin command>";
> +}
> +
> +// Serializing functions.
> +
> +template <typename T> static std::string serialize(T &I) {
> +  SmallString<2048> Buffer;
> +  llvm::BitstreamWriter Stream(Buffer);
> +  ClangDocBitcodeWriter Writer(Stream);
> +  Writer.emitBlock(I);
> +  return Buffer.str().str();
> +}
> +
> +static void parseFullComment(const FullComment *C, CommentInfo &CI) {
> +  ClangDocCommentVisitor Visitor(CI);
> +  Visitor.parseComment(C);
> +}
> +
> +static SymbolID getUSRForDecl(const Decl *D) {
> +  llvm::SmallString<128> USR;
> +  if (index::generateUSRForDecl(D, USR))
> +    return SymbolID();
> +  return hashUSR(USR);
> +}
> +
> +static RecordDecl *getDeclForType(const QualType &T) {
> +  auto *Ty = T->getAs<RecordType>();
> +  if (!Ty)
> +    return nullptr;
> +  return Ty->getDecl()->getDefinition();
> +}
> +
> +static void parseFields(RecordInfo &I, const RecordDecl *D) {
> +  for (const FieldDecl *F : D->fields()) {
> +    // FIXME: Set Access to the appropriate value.
> +    SymbolID Type;
> +    std::string Name;
> +    InfoType RefType;
> +    if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) {
> +      Type = getUSRForDecl(T);
> +      if (dyn_cast<EnumDecl>(T))
> +        RefType = InfoType::IT_enum;
> +      else if (dyn_cast<RecordDecl>(T))
> +        RefType = InfoType::IT_record;
> +      I.Members.emplace_back(Type, RefType, F->getQualifiedNameAsString());
> +    } else {
> +      Name = F->getTypeSourceInfo()->getType().getAsString();
> +      I.Members.emplace_back(Name, F->getQualifiedNameAsString());
> +    }
> +  }
> +}
> +
> +static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
> +  for (const EnumConstantDecl *E : D->enumerators())
> +    I.Members.emplace_back(E->getNameAsString());
> +}
> +
> +static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
> +  for (const ParmVarDecl *P : D->parameters()) {
> +    SymbolID Type;
> +    std::string Name;
> +    InfoType RefType;
> +    if (const auto *T = getDeclForType(P->getOriginalType())) {
> +      Type = getUSRForDecl(T);
> +      if (dyn_cast<EnumDecl>(T))
> +        RefType = InfoType::IT_enum;
> +      else if (dyn_cast<RecordDecl>(T))
> +        RefType = InfoType::IT_record;
> +      I.Params.emplace_back(Type, RefType, P->getQualifiedNameAsString());
> +    } else {
> +      Name = P->getOriginalType().getAsString();
> +      I.Params.emplace_back(Name, P->getQualifiedNameAsString());
> +    }
> +  }
> +}
> +
> +static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
> +  for (const CXXBaseSpecifier &B : D->bases()) {
> +    if (B.isVirtual())
> +      continue;
> +    if (const auto *P = getDeclForType(B.getType()))
> +      I.Parents.emplace_back(getUSRForDecl(P), InfoType::IT_record);
> +    else
> +      I.Parents.emplace_back(B.getType().getAsString());
> +  }
> +  for (const CXXBaseSpecifier &B : D->vbases()) {
> +    if (const auto *P = getDeclForType(B.getType()))
> +      I.VirtualParents.emplace_back(getUSRForDecl(P), InfoType::IT_record);
> +    else
> +      I.VirtualParents.emplace_back(B.getType().getAsString());
> +  }
> +}
> +
> +template <typename T>
> +static void
> +populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
> +                         const T *D) {
> +  const auto *DC = dyn_cast<DeclContext>(D);
> +  while ((DC = DC->getParent())) {
> +    if (const auto *N = dyn_cast<NamespaceDecl>(DC))
> +      Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_namespace);
> +    else if (const auto *N = dyn_cast<RecordDecl>(DC))
> +      Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_record);
> +    else if (const auto *N = dyn_cast<FunctionDecl>(DC))
> +      Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_function);
> +    else if (const auto *N = dyn_cast<EnumDecl>(DC))
> +      Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_enum);
> +  }
> +}
> +
> +template <typename T>
> +static void populateInfo(Info &I, const T *D, const FullComment *C) {
> +  I.USR = getUSRForDecl(D);
> +  I.Name = D->getNameAsString();
> +  populateParentNamespaces(I.Namespace, D);
> +  if (C) {
> +    I.Description.emplace_back();
> +    parseFullComment(C, I.Description.back());
> +  }
> +}
> +
> +template <typename T>
> +static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
> +                               int LineNumber, StringRef Filename) {
> +  populateInfo(I, D, C);
> +  if (D->isThisDeclarationADefinition())
> +    I.DefLoc.emplace(LineNumber, Filename);
> +  else
> +    I.Loc.emplace_back(LineNumber, Filename);
> +}
> +
> +static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
> +                                 const FullComment *FC, int LineNumber,
> +                                 StringRef Filename) {
> +  populateSymbolInfo(I, D, FC, LineNumber, Filename);
> +  if (const auto *T = getDeclForType(D->getReturnType())) {
> +    I.ReturnType.Type.USR = getUSRForDecl(T);
> +    if (dyn_cast<EnumDecl>(T))
> +      I.ReturnType.Type.RefType = InfoType::IT_enum;
> +    else if (dyn_cast<RecordDecl>(T))
> +      I.ReturnType.Type.RefType = InfoType::IT_record;
> +  } else {
> +    I.ReturnType.Type.UnresolvedName = D->getReturnType().getAsString();
> +  }
> +  parseParameters(I, D);
> +}
> +
> +std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
> +                     int LineNumber, llvm::StringRef File) {
> +  NamespaceInfo I;
> +  populateInfo(I, D, FC);
> +  return serialize(I);
> +}
> +
> +std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
> +                     llvm::StringRef File) {
> +  RecordInfo I;
> +  populateSymbolInfo(I, D, FC, LineNumber, File);
> +  I.TagType = D->getTagKind();
> +  parseFields(I, D);
> +  if (const auto *C = dyn_cast<CXXRecordDecl>(D))
> +    parseBases(I, C);
> +  return serialize(I);
> +}
> +
> +std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
> +                     int LineNumber, llvm::StringRef File) {
> +  FunctionInfo I;
> +  populateFunctionInfo(I, D, FC, LineNumber, File);
> +  I.Access = clang::AccessSpecifier::AS_none;
> +  return serialize(I);
> +}
> +
> +std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
> +                     int LineNumber, llvm::StringRef File) {
> +  FunctionInfo I;
> +  populateFunctionInfo(I, D, FC, LineNumber, File);
> +  I.IsMethod = true;
> +  I.Parent = Reference(getUSRForDecl(D->getParent()), InfoType::IT_record);
> +  I.Access = D->getAccess();
> +  return serialize(I);
> +}
> +
> +std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
> +                     llvm::StringRef File) {
> +  EnumInfo I;
> +  populateSymbolInfo(I, D, FC, LineNumber, File);
> +  I.Scoped = D->isScoped();
> +  parseEnumerators(I, D);
> +  return serialize(I);
> +}
> +
> +} // namespace serialize
> +} // namespace doc
> +} // namespace clang
> 
> Added: clang-tools-extra/trunk/clang-doc/Serialize.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Serialize.h?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/Serialize.h (added)
> +++ clang-tools-extra/trunk/clang-doc/Serialize.h Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,53 @@
> +//===-- Serializer.h - ClangDoc Serializer ----------------------*- 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 the serializing functions fro the clang-doc tool. Given
> +// a particular declaration, it collects the appropriate information and returns
> +// a serialized bitcode string for the declaration.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_SERIALIZE_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_SERIALIZE_H
> +
> +#include "Representation.h"
> +#include "clang/AST/AST.h"
> +#include "clang/AST/CommentVisitor.h"
> +#include <string>
> +#include <vector>
> +
> +using namespace clang::comments;
> +
> +namespace clang {
> +namespace doc {
> +namespace serialize {
> +
> +std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
> +                     int LineNumber, StringRef File);
> +std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
> +                     StringRef File);
> +std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
> +                     StringRef File);
> +std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
> +                     int LineNumber, StringRef File);
> +std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
> +                     int LineNumber, StringRef File);
> +
> +// Function to hash a given USR value for storage.
> +// As USRs (Unified Symbol Resolution) could be large, especially for functions
> +// with long type arguments, we use 160-bits SHA1(USR) values to
> +// guarantee the uniqueness of symbols while using a relatively small amount of
> +// memory (vs storing USRs directly).
> +SymbolID hashUSR(llvm::StringRef USR);
> +
> +} // namespace serialize
> +} // namespace doc
> +} // namespace clang
> +
> +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_SERIALIZE_H
> 
> Added: clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt (added)
> +++ clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,17 @@
> +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
> +
> +add_clang_executable(clang-doc
> +  ClangDocMain.cpp
> +  )
> +
> +target_link_libraries(clang-doc
> +  PRIVATE
> +  clangAST
> +  clangASTMatchers
> +  clangBasic
> +  clangFrontend
> +  clangDoc
> +  clangTooling
> +  clangToolingCore
> +  )
> +
> \ No newline at end of file
> 
> Added: 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=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp (added)
> +++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,114 @@
> +//===-- ClangDocMain.cpp - ClangDoc -----------------------------*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This tool for generating C and C++ documenation from source code
> +// and comments. Generally, it runs a LibTooling FrontendAction on source files,
> +// mapping each declaration in those files to its USR and serializing relevant
> +// information into LLVM bitcode. It then runs a pass over the collected
> +// declaration information, reducing by USR. There is an option to dump this
> +// intermediate result to bitcode. Finally, it hands the reduced information
> +// off to a generator, which does the final parsing from the intermediate
> +// representation to the desired output format.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "ClangDoc.h"
> +#include "clang/AST/AST.h"
> +#include "clang/AST/Decl.h"
> +#include "clang/ASTMatchers/ASTMatchFinder.h"
> +#include "clang/ASTMatchers/ASTMatchersInternal.h"
> +#include "clang/Driver/Options.h"
> +#include "clang/Frontend/FrontendActions.h"
> +#include "clang/Tooling/CommonOptionsParser.h"
> +#include "clang/Tooling/Execution.h"
> +#include "clang/Tooling/StandaloneExecution.h"
> +#include "clang/Tooling/Tooling.h"
> +#include "llvm/ADT/APFloat.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/Path.h"
> +#include "llvm/Support/Process.h"
> +#include "llvm/Support/Signals.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include <string>
> +
> +using namespace clang::ast_matchers;
> +using namespace clang::tooling;
> +using namespace clang;
> +
> +static llvm::cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
> +static llvm::cl::OptionCategory ClangDocCategory("clang-doc options");
> +
> +static llvm::cl::opt<std::string>
> +    OutDirectory("output",
> +                 llvm::cl::desc("Directory for outputting generated files."),
> +                 llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory));
> +
> +static llvm::cl::opt<bool>
> +    DumpMapperResult("dump-mapper",
> +                     llvm::cl::desc("Dump mapper results to bitcode file."),
> +                     llvm::cl::init(false), 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));
> +
> +int main(int argc, const char **argv) {
> +  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
> +  std::error_code OK;
> +
> +  auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
> +      argc, argv, ClangDocCategory);
> +
> +  if (!Exec) {
> +    llvm::errs() << toString(Exec.takeError()) << "\n";
> +    return 1;
> +  }
> +
> +  ArgumentsAdjuster ArgAdjuster;
> +  if (!DoxygenOnly)
> +    ArgAdjuster = combineAdjusters(
> +        getInsertArgumentAdjuster("-fparse-all-comments",
> +                                  tooling::ArgumentInsertPosition::END),
> +        ArgAdjuster);
> +
> +  // Mapping phase
> +  llvm::outs() << "Mapping decls...\n";
> +  auto Err = Exec->get()->execute(doc::newMapperActionFactory(
> +                                      Exec->get()->getExecutionContext()),
> +                                  ArgAdjuster);
> +  if (Err)
> +    llvm::errs() << toString(std::move(Err)) << "\n";
> +
> +  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;
> +      }
> +      OS << Value;
> +      OS.close();
> +    });
> +  }
> +
> +  return 0;
> +}
> 
> Modified: clang-tools-extra/trunk/test/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/CMakeLists.txt?rev=328270&r1=328269&r2=328270&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/test/CMakeLists.txt (original)
> +++ clang-tools-extra/trunk/test/CMakeLists.txt Thu Mar 22 16:34:46 2018
> @@ -37,10 +37,14 @@ set(CLANG_TOOLS_TEST_DEPS
>     # For the clang-apply-replacements test that uses clang-rename.
>     clang-rename
>   
> +  # For the clang-doc tests that emit bitcode files.
> +  llvm-bcanalyzer
> +
>     # Individual tools we test.
>     clang-apply-replacements
>     clang-change-namespace
>     clangd
> +  clang-doc
>     clang-include-fixer
>     clang-move
>     clang-query
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-class-in-class.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-class-in-class.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-class-in-class.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-class-in-class.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,35 @@
> +// RUN: rm -rf %t
> +// RUN: mkdir %t
> +// RUN: echo "" > %t/compile_flags.txt
> +// RUN: cp "%s" "%t/test.cpp"
> +// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
> +// RUN: llvm-bcanalyzer %t/docs/bc/641AB4A3D36399954ACDE29C7A8833032BF40472.bc --dump | FileCheck %s --check-prefix CHECK-X-Y
> +// RUN: llvm-bcanalyzer %t/docs/bc/CA7C7935730B5EACD25F080E9C83FA087CCDC75E.bc --dump | FileCheck %s --check-prefix CHECK-X
> +
> +class X {
> +  class Y {};
> +};
> +
> +// CHECK-X: <BLOCKINFO_BLOCK/>
> +// CHECK-X-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-X-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-X-NEXT: </VersionBlock>
> +// CHECK-X-NEXT: <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=7 op0=9 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-X-NEXT: <TagType abbrevid=9 op0=3/>
> +// CHECK-X-NEXT: </RecordBlock>
> +
> +
> +// CHECK-X-Y: <BLOCKINFO_BLOCK/>
> +// CHECK-X-Y-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-X-Y-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-X-Y-NEXT: </VersionBlock>
> +// CHECK-X-Y-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-X-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-X-Y-NEXT: <Name abbrevid=5 op0=1/> blob data = 'Y'
> +  // CHECK-X-Y-NEXT: <Namespace abbrevid=6 op0=1 op1=40/> blob data = 'CA7C7935730B5EACD25F080E9C83FA087CCDC75E'
> +  // CHECK-X-Y-NEXT: <DefLocation abbrevid=7 op0=10 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-X-Y-NEXT: <TagType abbrevid=9 op0=3/>
> +// CHECK-X-Y-NEXT: </RecordBlock>
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-class-in-function.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-class-in-function.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-class-in-function.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-class-in-function.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,41 @@
> +// This test requires Linux due to the system-dependent USR for the
> +// inner class.
> +// 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-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
> +// RUN: llvm-bcanalyzer %t/docs/bc/B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E.bc --dump | FileCheck %s --check-prefix CHECK-H
> +// RUN: llvm-bcanalyzer %t/docs/bc/01A95F3F73F53281B3E50109A577FD2493159365.bc --dump | FileCheck %s --check-prefix CHECK-H-I
> +
> +void H() {
> +  class I {};
> +}
> +
> +// CHECK-H: <BLOCKINFO_BLOCK/>
> +// CHECK-H-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-H-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-H-NEXT: </VersionBlock>
> +// CHECK-H-NEXT: <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=7 op0=12 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-H-NEXT: <TypeBlock NumWords=4 BlockCodeSize=4>
> +    // CHECK-H-NEXT: <Type abbrevid=4 op0=4 op1=4/> blob data = 'void'
> +  // CHECK-H-NEXT: </TypeBlock>
> +// CHECK-H-NEXT: </FunctionBlock>
> +
> +// CHECK-H-I: <BLOCKINFO_BLOCK/>
> +// CHECK-H-I-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-H-I-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-H-I-NEXT: </VersionBlock>
> +// CHECK-H-I-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-H-I-NEXT: <USR abbrevid=4 op0=20 op1=1 op2=169 op3=95 op4=63 op5=115 op6=245 op7=50 op8=129 op9=179 op10=229 op11=1 op12=9 op13=165 op14=119 op15=253 op16=36 op17=147 op18=21 op19=147 op20=101/>
> +  // CHECK-H-I-NEXT: <Name abbrevid=5 op0=1/> blob data = 'I'
> +  // CHECK-H-I-NEXT: <Namespace abbrevid=6 op0=2 op1=40/> blob data = 'B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E'
> +  // CHECK-H-I-NEXT: <DefLocation abbrevid=7 op0=13 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-H-I-NEXT: <TagType abbrevid=9 op0=3/>
> +// CHECK-H-I-NEXT: </RecordBlock>
> +
> +
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-class.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-class.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-class.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-class.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,19 @@
> +// RUN: rm -rf %t
> +// RUN: mkdir %t
> +// RUN: echo "" > %t/compile_flags.txt
> +// RUN: cp "%s" "%t/test.cpp"
> +// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
> +// RUN: llvm-bcanalyzer %t/docs/bc/289584A8E0FF4178A794622A547AA622503967A1.bc --dump | FileCheck %s
> +
> +class E {};
> +
> +// CHECK: <BLOCKINFO_BLOCK/>
> +// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-NEXT: </VersionBlock>
> +// CHECK-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-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-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
> +  // CHECK-NEXT: <DefLocation abbrevid=7 op0=8 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-NEXT: <TagType abbrevid=9 op0=3/>
> +// CHECK-NEXT: </RecordBlock>
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-comments.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-comments.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-comments.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-comments.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,172 @@
> +// RUN: rm -rf %t
> +// RUN: mkdir %t
> +// RUN: echo "" > %t/compile_flags.txt
> +// RUN: cp "%s" "%t/test.cpp"
> +// RUN: clang-doc --dump-mapper -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 int
> +int F(int I, int J);
> +
> +// CHECK: <BLOCKINFO_BLOCK/>
> +// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
> +// 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=351 BlockCodeSize=4>
> +    // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
> +    // CHECK-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
> +      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
> +      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
> +      // CHECK-NEXT: </CommentBlock>
> +    // CHECK-NEXT: </CommentBlock>
> +    // CHECK-NEXT: <CommentBlock NumWords=31 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=19 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
> +        // CHECK-NEXT: <CommentBlock NumWords=11 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=37 BlockCodeSize=4>
> +      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
> +      // CHECK-NEXT: <CommentBlock NumWords=13 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=14 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=83 BlockCodeSize=4>
> +      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
> +      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
> +      // CHECK-NEXT: </CommentBlock>
> +      // CHECK-NEXT: <CommentBlock NumWords=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: </CommentBlock>
> +      // CHECK-NEXT: <CommentBlock NumWords=10 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
> +        // CHECK-NEXT: <Text abbrevid=5 op0=14/> blob data = ' class="test">'
> +      // CHECK-NEXT: </CommentBlock>
> +      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
> +      // CHECK-NEXT: </CommentBlock>
> +      // CHECK-NEXT: <CommentBlock NumWords=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=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=5 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
> +      // CHECK-NEXT: </CommentBlock>
> +      // CHECK-NEXT: <CommentBlock NumWords=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=13 BlockCodeSize=4>
> +      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
> +      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
> +      // CHECK-NEXT: </CommentBlock>
> +    // CHECK-NEXT: </CommentBlock>
> +    // CHECK-NEXT: <CommentBlock NumWords=32 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=16 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=13 BlockCodeSize=4>
> +      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
> +      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
> +      // CHECK-NEXT: </CommentBlock>
> +    // CHECK-NEXT: </CommentBlock>
> +    // CHECK-NEXT: <CommentBlock NumWords=39 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=25 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
> +        // CHECK-NEXT: <CommentBlock NumWords=10 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=5 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=38 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=25 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
> +        // CHECK-NEXT: <CommentBlock NumWords=10 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=5 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=27 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=15 BlockCodeSize=4>
> +        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
> +        // CHECK-NEXT: <CommentBlock NumWords=7 BlockCodeSize=4>
> +          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
> +          // CHECK-NEXT: <Text abbrevid=5 op0=4/> blob data = ' int'
> +        // CHECK-NEXT: </CommentBlock>
> +      // CHECK-NEXT: </CommentBlock>
> +    // CHECK-NEXT: </CommentBlock>
> +  // CHECK-NEXT: </CommentBlock>
> +  // CHECK-NEXT: <Location abbrevid=8 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-NEXT: <TypeBlock NumWords=4 BlockCodeSize=4>
> +    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +  // CHECK-NEXT: </TypeBlock>
> +  // CHECK-NEXT: <FieldTypeBlock NumWords=6 BlockCodeSize=4>
> +    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +    // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'I'
> +  // CHECK-NEXT: </FieldTypeBlock>
> +  // CHECK-NEXT: <FieldTypeBlock NumWords=6 BlockCodeSize=4>
> +    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +    // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'J'
> +  // CHECK-NEXT: </FieldTypeBlock>
> +// CHECK-NEXT: </FunctionBlock>
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-enum.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-enum.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-enum.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-enum.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,36 @@
> +// RUN: rm -rf %t
> +// RUN: mkdir %t
> +// RUN: echo "" > %t/compile_flags.txt
> +// RUN: cp "%s" "%t/test.cpp"
> +// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
> +// RUN: llvm-bcanalyzer %t/docs/bc/FC07BD34D5E77782C263FA944447929EA8753740.bc --dump | FileCheck %s --check-prefix CHECK-B
> +// RUN: llvm-bcanalyzer %t/docs/bc/020E6C32A700C3170C009FCCD41671EDDBEAF575.bc --dump | FileCheck %s --check-prefix CHECK-C
> +
> +enum B { X, Y };
> +
> +// CHECK-B: <BLOCKINFO_BLOCK/>
> +// CHECK-B-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-B-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-B-NEXT: </VersionBlock>
> +// CHECK-B-NEXT: <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=7 op0=9 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-B-NEXT: <Member abbrevid=9 op0=1/> blob data = 'X'
> +  // CHECK-B-NEXT: <Member abbrevid=9 op0=1/> blob data = 'Y'
> +// CHECK-B-NEXT: </EnumBlock>
> +
> +enum class C { A, B };
> +
> +// CHECK-C: <BLOCKINFO_BLOCK/>
> +// CHECK-C-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-C-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-C-NEXT: </VersionBlock>
> +// CHECK-C-NEXT: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-C-NEXT: <USR abbrevid=4 op0=20 op1=2 op2=14 op3=108 op4=50 op5=167 op6=0 op7=195 op8=23 op9=12 op10=0 op11=159 op12=204 op13=212 op14=22 op15=113 op16=237 op17=219 op18=234 op19=245 op20=117/>
> +  // CHECK-C-NEXT: <Name abbrevid=5 op0=1/> blob data = 'C'
> +  // CHECK-C-NEXT: <DefLocation abbrevid=7 op0=23 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-C-NEXT: <Scoped abbrevid=10 op0=1/>
> +  // CHECK-C-NEXT: <Member abbrevid=9 op0=1/> blob data = 'A'
> +  // CHECK-C-NEXT: <Member abbrevid=9 op0=1/> blob data = 'B'
> +// CHECK-C-NEXT: </EnumBlock>
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-function.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-function.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-function.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-function.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,25 @@
> +// RUN: rm -rf %t
> +// RUN: mkdir %t
> +// RUN: echo "" > %t/compile_flags.txt
> +// RUN: cp "%s" "%t/test.cpp"
> +// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
> +// RUN: llvm-bcanalyzer %t/docs/bc/A44B32CC3C087C9AF75DAF50DE193E85E7B2C16B.bc --dump | FileCheck %s
> +
> +int F(int param) { return param; }
> +
> +// CHECK: <BLOCKINFO_BLOCK/>
> +// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-NEXT: </VersionBlock>
> +// CHECK-NEXT: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=164 op2=75 op3=50 op4=204 op5=60 op6=8 op7=124 op8=154 op9=247 op10=93 op11=175 op12=80 op13=222 op14=25 op15=62 op16=133 op17=231 op18=178 op19=193 op20=107/>
> +  // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
> +  // CHECK-NEXT: <DefLocation abbrevid=7 op0=8 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-NEXT: <TypeBlock NumWords=4 BlockCodeSize=4>
> +    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +  // CHECK-NEXT: </TypeBlock>
> +  // CHECK-NEXT: <FieldTypeBlock NumWords=7 BlockCodeSize=4>
> +    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +    // CHECK-NEXT: <Name abbrevid=5 op0=5/> blob data = 'param'
> +  // CHECK-NEXT: </FieldTypeBlock>
> +// CHECK-NEXT: </FunctionBlock>
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-method.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-method.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-method.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-method.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,43 @@
> +// RUN: rm -rf %t
> +// RUN: mkdir %t
> +// RUN: echo "" > %t/compile_flags.txt
> +// RUN: cp "%s" "%t/test.cpp"
> +// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
> +// RUN: llvm-bcanalyzer %t/docs/bc/F0F9FC65FC90F54F690144A7AFB15DFC3D69B6E6.bc --dump | FileCheck %s --check-prefix CHECK-G-F
> +// RUN: llvm-bcanalyzer %t/docs/bc/4202E8BF0ECB12AE354C8499C52725B0EE30AED5.bc --dump | FileCheck %s --check-prefix CHECK-G
> +
> +class G {
> +public:
> +	int Method(int param) { return param; }
> +};
> +
> +// CHECK-G: <BLOCKINFO_BLOCK/>
> +// CHECK-G-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-G-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-G-NEXT: </VersionBlock>
> +// CHECK-G-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-G-NEXT: <USR abbrevid=4 op0=20 op1=66 op2=2 op3=232 op4=191 op5=14 op6=203 op7=18 op8=174 op9=53 op10=76 op11=132 op12=153 op13=197 op14=39 op15=37 op16=176 op17=238 op18=48 op19=174 op20=213/>
> +  // CHECK-G-NEXT: <Name abbrevid=5 op0=1/> blob data = 'G'
> +  // CHECK-G-NEXT: <DefLocation abbrevid=7 op0=9 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-G-NEXT: <TagType abbrevid=9 op0=3/>
> +// CHECK-G-NEXT: </RecordBlock>
> +
> +// CHECK-G-F: <BLOCKINFO_BLOCK/>
> +// CHECK-G-F-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-G-F-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-G-F-NEXT: </VersionBlock>
> +// CHECK-G-F-NEXT: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-G-F-NEXT: <USR abbrevid=4 op0=20 op1=240 op2=249 op3=252 op4=101 op5=252 op6=144 op7=245 op8=79 op9=105 op10=1 op11=68 op12=167 op13=175 op14=177 op15=93 op16=252 op17=61 op18=105 op19=182 op20=230/>
> +  // CHECK-G-F-NEXT: <Name abbrevid=5 op0=6/> blob data = 'Method'
> +  // CHECK-G-F-NEXT: <Namespace abbrevid=6 op0=1 op1=40/> blob data = '4202E8BF0ECB12AE354C8499C52725B0EE30AED5'
> +  // CHECK-G-F-NEXT: <IsMethod abbrevid=11 op0=1/>
> +  // CHECK-G-F-NEXT: <DefLocation abbrevid=7 op0=11 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-G-F-NEXT: <Parent abbrevid=9 op0=1 op1=40/> blob data = '4202E8BF0ECB12AE354C8499C52725B0EE30AED5'
> +  // CHECK-G-F-NEXT: <TypeBlock NumWords=4 BlockCodeSize=4>
> +    // CHECK-G-F-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +  // CHECK-G-F-NEXT: </TypeBlock>
> +  // CHECK-G-F-NEXT: <FieldTypeBlock NumWords=7 BlockCodeSize=4>
> +    // CHECK-G-F-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +    // CHECK-G-F-NEXT: <Name abbrevid=5 op0=5/> blob data = 'param'
> +  // CHECK-G-F-NEXT: </FieldTypeBlock>
> +// CHECK-G-F-NEXT: </FunctionBlock>
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-namespace.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-namespace.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-namespace.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-namespace.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,17 @@
> +// RUN: rm -rf %t
> +// RUN: mkdir %t
> +// RUN: echo "" > %t/compile_flags.txt
> +// RUN: cp "%s" "%t/test.cpp"
> +// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
> +// RUN: llvm-bcanalyzer %t/docs/bc/8D042EFFC98B373450BC6B5B90A330C25A150E9C.bc --dump | FileCheck %s
> +
> +namespace A {}
> +
> +// CHECK: <BLOCKINFO_BLOCK/>
> +// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-NEXT: </VersionBlock>
> +// CHECK-NEXT: <NamespaceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-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-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
> +// CHECK-NEXT: </NamespaceBlock>
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-struct.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-struct.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-struct.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-struct.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,23 @@
> +// RUN: rm -rf %t
> +// RUN: mkdir %t
> +// RUN: echo "" > %t/compile_flags.txt
> +// RUN: cp "%s" "%t/test.cpp"
> +// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
> +// RUN: llvm-bcanalyzer %t/docs/bc/06B5F6A19BA9F6A832E127C9968282B94619B210.bc --dump | FileCheck %s
> +
> +struct C { int i; };
> +
> +// CHECK: <BLOCKINFO_BLOCK/>
> +// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-NEXT: </VersionBlock>
> +// CHECK-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-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-NEXT: <Name abbrevid=5 op0=1/> blob data = 'C'
> +  // CHECK-NEXT: <DefLocation abbrevid=7 op0=8 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-NEXT: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
> +    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +    // CHECK-NEXT: <Name abbrevid=5 op0=4/> blob data = 'C::i'
> +    // CHECK-NEXT: <Access abbrevid=6 op0=3/>
> +  // CHECK-NEXT: </MemberTypeBlock>
> +// CHECK-NEXT: </RecordBlock>
> 
> Added: clang-tools-extra/trunk/test/clang-doc/mapper-union.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/mapper-union.cpp?rev=328270&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/clang-doc/mapper-union.cpp (added)
> +++ clang-tools-extra/trunk/test/clang-doc/mapper-union.cpp Thu Mar 22 16:34:46 2018
> @@ -0,0 +1,29 @@
> +// RUN: rm -rf %t
> +// RUN: mkdir %t
> +// RUN: echo "" > %t/compile_flags.txt
> +// RUN: cp "%s" "%t/test.cpp"
> +// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
> +// RUN: llvm-bcanalyzer %t/docs/bc/0B8A6B938B939B77C6325CCCC8AA3E938BF9E2E8.bc --dump | FileCheck %s
> +
> +union D { int X; int Y; };
> +
> +// CHECK: <BLOCKINFO_BLOCK/>
> +// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
> +  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
> +// CHECK-NEXT: </VersionBlock>
> +// CHECK-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
> +  // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=11 op2=138 op3=107 op4=147 op5=139 op6=147 op7=155 op8=119 op9=198 op10=50 op11=92 op12=204 op13=200 op14=170 op15=62 op16=147 op17=139 op18=249 op19=226 op20=232/>
> +  // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D'
> +  // CHECK-NEXT: <DefLocation abbrevid=7 op0=8 op1={{[0-9]*}}/> blob data = '{{.*}}'
> +  // CHECK-NEXT: <TagType abbrevid=9 op0=2/>
> +  // CHECK-NEXT: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
> +    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +    // CHECK-NEXT: <Name abbrevid=5 op0=4/> blob data = 'D::X'
> +    // CHECK-NEXT: <Access abbrevid=6 op0=3/>
> +  // CHECK-NEXT: </MemberTypeBlock>
> +  // CHECK-NEXT: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
> +    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
> +    // CHECK-NEXT: <Name abbrevid=5 op0=4/> blob data = 'D::Y'
> +    // CHECK-NEXT: <Access abbrevid=6 op0=3/>
> +  // CHECK-NEXT: </MemberTypeBlock>
> +// CHECK-NEXT: </RecordBlock>
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
> 


More information about the cfe-commits mailing list