60 changes: 48 additions & 12 deletions clang-tools-extra/clang-doc/Representation.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
///===-- Representation.h - ClangDoc Represenation --------------*- C++ -*-===//
///===-- Representation.h - ClangDoc Representation -------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
Expand Down Expand Up @@ -26,6 +26,7 @@
namespace clang {
namespace doc {

// SHA1'd hash of a USR.
using SymbolID = std::array<uint8_t, 20>;

struct Info;
Expand All @@ -40,7 +41,8 @@ enum class InfoType {
// A representation of a parsed comment.
struct CommentInfo {
CommentInfo() = default;
CommentInfo(CommentInfo &&Other) : Children(std::move(Other.Children)) {}
CommentInfo(CommentInfo &Other) = delete;
CommentInfo(CommentInfo &&Other) = default;

SmallString<16> Kind; // Kind of comment (TextComment, InlineCommandComment,
// HTMLStartTagComment, HTMLEndTagComment,
Expand Down Expand Up @@ -128,28 +130,46 @@ struct Location {
/// A base struct for Infos.
struct Info {
Info() = default;
Info(Info &&Other) : Description(std::move(Other.Description)) {}
virtual ~Info() = default;

SymbolID USR; // Unique identifier for the decl described by this Info.
SmallString<16> Name; // Unqualified name of the decl.
Info(InfoType IT) : IT(IT) {}
Info(const Info &Other) = delete;
Info(Info &&Other) = default;

SymbolID USR =
SymbolID(); // Unique identifier for the decl described by this Info.
const InfoType IT = InfoType::IT_default; // InfoType of this particular Info.
SmallString<16> Name; // Unqualified name of the decl.
llvm::SmallVector<Reference, 4>
Namespace; // List of parent namespaces for this decl.
std::vector<CommentInfo> Description; // Comment description of this decl.

void mergeBase(Info &&I);
bool mergeable(const Info &Other);
};

// Info for namespaces.
struct NamespaceInfo : public Info {};
struct NamespaceInfo : public Info {
NamespaceInfo() : Info(InfoType::IT_namespace) {}

void merge(NamespaceInfo &&I);
};

// Info for symbols.
struct SymbolInfo : public Info {
SymbolInfo(InfoType IT) : Info(IT) {}

void merge(SymbolInfo &&I);

llvm::Optional<Location> DefLoc; // Location where this decl is defined.
llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
};

// TODO: Expand to allow for documenting templating and default args.
// Info for functions.
struct FunctionInfo : public SymbolInfo {
FunctionInfo() : SymbolInfo(InfoType::IT_function) {}

void merge(FunctionInfo &&I);

bool IsMethod = false; // Indicates whether this function is a class method.
Reference Parent; // Reference to the parent class decl for this method.
TypeInfo ReturnType; // Info about the return type of this function.
Expand All @@ -163,26 +183,42 @@ struct FunctionInfo : public SymbolInfo {
// friend classes
// Info for types.
struct RecordInfo : public SymbolInfo {
TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record (struct,
// class, union, interface).
RecordInfo() : SymbolInfo(InfoType::IT_record) {}

void merge(RecordInfo &&I);

TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record
// (struct, class, union,
// interface).
llvm::SmallVector<MemberTypeInfo, 4>
Members; // List of info about record members.
llvm::SmallVector<Reference, 4> Parents; // List of base/parent records (does
// not include virtual parents).
llvm::SmallVector<Reference, 4> Parents; // List of base/parent records
// (does not include virtual
// parents).
llvm::SmallVector<Reference, 4>
VirtualParents; // List of virtual base/parent records.
};

// TODO: Expand to allow for documenting templating.
// Info for types.
struct EnumInfo : public SymbolInfo {
EnumInfo() : SymbolInfo(InfoType::IT_enum) {}

void merge(EnumInfo &&I);

bool Scoped =
false; // Indicates whether this enum is scoped (e.g. enum class).
llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members.
};

// TODO: Add functionality to include separate markdown pages.

// A standalone function to call to merge a vector of infos into one.
// This assumes that all infos in the vector are of the same type, and will fail
// if they are different.
llvm::Expected<std::unique_ptr<Info>>
mergeInfos(std::vector<std::unique_ptr<Info>> &Values);

} // namespace doc
} // namespace clang

Expand Down
138 changes: 113 additions & 25 deletions clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
//
//===----------------------------------------------------------------------===//

#include "BitcodeReader.h"
#include "BitcodeWriter.h"
#include "ClangDoc.h"
#include "Representation.h"
#include "clang/AST/AST.h"
#include "clang/AST/Decl.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
Expand All @@ -30,6 +33,7 @@
#include "clang/Tooling/StandaloneExecution.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
Expand All @@ -54,14 +58,66 @@ static llvm::cl::opt<bool>
llvm::cl::desc("Dump mapper results to bitcode file."),
llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));

static llvm::cl::opt<bool> DumpIntermediateResult(
"dump-intermediate",
llvm::cl::desc("Dump intermediate results to bitcode file."),
llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));

enum OutputFormatTy {
yaml,
};

static llvm::cl::opt<OutputFormatTy>
Format("format", llvm::cl::desc("Format for outputted docs."),
llvm::cl::values(clEnumVal(yaml, "Documentation in YAML format.")),
llvm::cl::init(yaml), llvm::cl::cat(ClangDocCategory));

static llvm::cl::opt<bool> DoxygenOnly(
"doxygen",
llvm::cl::desc("Use only doxygen-style comments to generate docs."),
llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));

bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) {
std::error_code OK;
llvm::SmallString<128> DocsRootPath;
if (ClearDirectory) {
std::error_code RemoveStatus = llvm::sys::fs::remove_directories(DirName);
if (RemoveStatus != OK) {
llvm::errs() << "Unable to remove existing documentation directory for "
<< DirName << ".\n";
return true;
}
}
std::error_code DirectoryStatus = llvm::sys::fs::create_directories(DirName);
if (DirectoryStatus != OK) {
llvm::errs() << "Unable to create documentation directories.\n";
return true;
}
return false;
}

bool DumpResultToFile(const Twine &DirName, const Twine &FileName,
StringRef Buffer, bool ClearDirectory = false) {
std::error_code OK;
llvm::SmallString<128> IRRootPath;
llvm::sys::path::native(OutDirectory, IRRootPath);
llvm::sys::path::append(IRRootPath, DirName);
if (CreateDirectory(IRRootPath, ClearDirectory))
return true;
llvm::sys::path::append(IRRootPath, FileName);
std::error_code OutErrorInfo;
llvm::raw_fd_ostream OS(IRRootPath, OutErrorInfo, llvm::sys::fs::F_None);
if (OutErrorInfo != OK) {
llvm::errs() << "Error opening documentation file.\n";
return true;
}
OS << Buffer;
OS.close();
return false;
}

int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
std::error_code OK;

auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
argc, argv, ClangDocCategory);
Expand All @@ -80,34 +136,66 @@ int main(int argc, const char **argv) {

// Mapping phase
llvm::outs() << "Mapping decls...\n";
auto Err = Exec->get()->execute(doc::newMapperActionFactory(
Exec->get()->getExecutionContext()),
ArgAdjuster);
if (Err)
auto Err = Exec->get()->execute(
doc::newMapperActionFactory(Exec->get()->getExecutionContext()),
ArgAdjuster);
if (Err) {
llvm::errs() << toString(std::move(Err)) << "\n";
return 1;
}

if (DumpMapperResult) {
Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
StringRef Value) {
SmallString<128> IRRootPath;
llvm::sys::path::native(OutDirectory, IRRootPath);
llvm::sys::path::append(IRRootPath, "bc");
std::error_code DirectoryStatus =
llvm::sys::fs::create_directories(IRRootPath);
if (DirectoryStatus != OK) {
llvm::errs() << "Unable to create documentation directories.\n";
return;
}
llvm::sys::path::append(IRRootPath, Key + ".bc");
std::error_code OutErrorInfo;
llvm::raw_fd_ostream OS(IRRootPath, OutErrorInfo, llvm::sys::fs::F_None);
if (OutErrorInfo != OK) {
llvm::errs() << "Error opening documentation file.\n";
return;
bool Err = false;
Exec->get()->getToolResults()->forEachResult(
[&](StringRef Key, StringRef Value) {
Err = DumpResultToFile("bc", Key + ".bc", Value);
});
if (Err)
llvm::errs() << "Error dumping map results.\n";
return Err;
}

// Collect values into output by key.
llvm::outs() << "Collecting infos...\n";
llvm::StringMap<std::vector<std::unique_ptr<doc::Info>>> MapOutput;

// In ToolResults, the Key is the hashed USR and the value is the
// bitcode-encoded representation of the Info object.
Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
StringRef Value) {
llvm::BitstreamCursor Stream(Value);
doc::ClangDocBitcodeReader Reader(Stream);
auto Infos = Reader.readBitcode();
for (auto &I : Infos) {
auto R =
MapOutput.try_emplace(Key, std::vector<std::unique_ptr<doc::Info>>());
R.first->second.emplace_back(std::move(I));
}
});

// Reducing phase
llvm::outs() << "Reducing " << MapOutput.size() << " infos...\n";
llvm::StringMap<std::unique_ptr<doc::Info>> ReduceOutput;
for (auto &Group : MapOutput) {
auto Reduced = doc::mergeInfos(Group.getValue());
if (!Reduced)
llvm::errs() << llvm::toString(Reduced.takeError());

if (DumpIntermediateResult) {
SmallString<4096> Buffer;
llvm::BitstreamWriter Stream(Buffer);
doc::ClangDocBitcodeWriter Writer(Stream);
Writer.dispatchInfoForWrite(Reduced.get().get());
if (DumpResultToFile("bc", Group.getKey() + ".bc", Buffer)) {
llvm::errs() << "Error writing " << Group.getKey() << " to file.\n";
continue;
}
OS << Value;
OS.close();
});
}

ReduceOutput.insert(
std::make_pair(Group.getKey(), std::move(Reduced.get())));

// FIXME: Add support for emitting different output formats.
}

return 0;
Expand Down
197 changes: 197 additions & 0 deletions clang-tools-extra/test/clang-doc/bc-comment.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: echo "" > %t/compile_flags.txt
// RUN: cp "%s" "%t/test.cpp"
// RUN: clang-doc --dump-intermediate -doxygen -p %t %t/test.cpp -output=%t/docs
// RUN: llvm-bcanalyzer %t/docs/bc/7574630614A535710E5A6ABCFFF98BCA2D06A4CA.bc --dump | FileCheck %s

/// \brief Brief description.
///
/// Extended description that
/// continues onto the next line.
///
/// <ul class="test">
/// <li> Testing.
/// </ul>
///
/// \verbatim
/// The description continues.
/// \endverbatim
/// --
/// \param [out] I is a parameter.
/// \param J is a parameter.
/// \return void
void F(int I, int J);

/// Bonus comment on definition
void F(int I, int J) {}

// CHECK: <BLOCKINFO_BLOCK/>
// CHECK-NEXT: <VersionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Version abbrevid=4 op0=2/>
// CHECK-NEXT: </VersionBlock>
// CHECK-NEXT: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <USR abbrevid=4 op0=20 op1=117 op2=116 op3=99 op4=6 op5=20 op6=165 op7=53 op8=113 op9=14 op10=90 op11=106 op12=188 op13=255 op14=249 op15=139 op16=202 op17=45 op18=6 op19=164 op20=202/>
// CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment'
// CHECK-NEXT: <Name abbrevid=6 op0=5/> blob data = 'brief'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: <Text abbrevid=5 op0=19/> blob data = ' Brief description.'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: <Text abbrevid=5 op0=26/> blob data = ' Extended description that'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: <Text abbrevid=5 op0=30/> blob data = ' continues onto the next line.'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment'
// CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul'
// CHECK-NEXT: <AttrKey abbrevid=12 op0=5/> blob data = 'class'
// CHECK-NEXT: <AttrVal abbrevid=13 op0=4/> blob data = 'test'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment'
// CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'li'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: <Text abbrevid=5 op0=9/> blob data = ' Testing.'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=17/> blob data = 'HTMLEndTagComment'
// CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul'
// CHECK-NEXT: <SelfClosing abbrevid=10 op0=1/>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=20/> blob data = 'VerbatimBlockComment'
// CHECK-NEXT: <Name abbrevid=6 op0=8/> blob data = 'verbatim'
// CHECK-NEXT: <CloseName abbrevid=9 op0=11/> blob data = 'endverbatim'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=24/> blob data = 'VerbatimBlockLineComment'
// CHECK-NEXT: <Text abbrevid=5 op0=27/> blob data = ' The description continues.'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: <Text abbrevid=5 op0=3/> blob data = ' --'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment'
// CHECK-NEXT: <Direction abbrevid=7 op0=5/> blob data = '[out]'
// CHECK-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'I'
// CHECK-NEXT: <Explicit abbrevid=11 op0=1/>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment'
// CHECK-NEXT: <Direction abbrevid=7 op0=4/> blob data = '[in]'
// CHECK-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'J'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment'
// CHECK-NEXT: <Name abbrevid=6 op0=6/> blob data = 'return'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: <Text abbrevid=5 op0=5/> blob data = ' void'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
// CHECK-NEXT: <CommentBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
// CHECK-NEXT: <Text abbrevid=5 op0=28/> blob data = ' Bonus comment on definition'
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: </CommentBlock>
// CHECK-NEXT: <DefLocation abbrevid=6 op0=27 op1={{[0-9]*}}/> blob data = '{{.*}}'
// CHECK-NEXT: <Location abbrevid=7 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}'
// CHECK-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
// CHECK-NEXT: <Field abbrevid=7 op0=4/>
// CHECK-NEXT: </ReferenceBlock>
// CHECK-NEXT: </TypeBlock>
// CHECK-NEXT: <FieldTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
// CHECK-NEXT: <Field abbrevid=7 op0=4/>
// CHECK-NEXT: </ReferenceBlock>
// CHECK-NEXT: <Name abbrevid=4 op0=1/> blob data = 'I'
// CHECK-NEXT: </FieldTypeBlock>
// CHECK-NEXT: <FieldTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
// CHECK-NEXT: <Field abbrevid=7 op0=4/>
// CHECK-NEXT: </ReferenceBlock>
// CHECK-NEXT: <Name abbrevid=4 op0=1/> blob data = 'J'
// CHECK-NEXT: </FieldTypeBlock>
// CHECK-NEXT: </FunctionBlock>
109 changes: 109 additions & 0 deletions clang-tools-extra/test/clang-doc/bc-namespace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: echo "" > %t/compile_flags.txt
// RUN: cp "%s" "%t/test.cpp"
// RUN: clang-doc --dump-intermediate -doxygen -p %t %t/test.cpp -output=%t/docs
// RUN: llvm-bcanalyzer %t/docs/bc/8D042EFFC98B373450BC6B5B90A330C25A150E9C.bc --dump | FileCheck %s --check-prefix CHECK-A
// RUN: llvm-bcanalyzer %t/docs/bc/E21AF79E2A9D02554BA090D10DF39FE273F5CDB5.bc --dump | FileCheck %s --check-prefix CHECK-B
// RUN: llvm-bcanalyzer %t/docs/bc/39D3C95A5F7CE2BA4937BD7B01BAE09EBC2AD8AC.bc --dump | FileCheck %s --check-prefix CHECK-F
// RUN: llvm-bcanalyzer %t/docs/bc/9A82CB33ED0FDF81EE383D31CD0957D153C5E840.bc --dump | FileCheck %s --check-prefix CHECK-FUNC
// RUN: llvm-bcanalyzer %t/docs/bc/E9ABF7E7E2425B626723D41E76E4BC7E7A5BD775.bc --dump | FileCheck %s --check-prefix CHECK-E

namespace A {
// CHECK-A: <NamespaceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-A-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
// CHECK-A-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
// CHECK-A-NEXT: </NamespaceBlock>

void f();

} // namespace A

namespace A {

void f(){};
// CHECK-F: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=57 op2=211 op3=201 op4=90 op5=95 op6=124 op7=226 op8=186 op9=73 op10=55 op11=189 op12=123 op13=1 op14=186 op15=224 op16=158 op17=188 op18=42 op19=216 op20=172/>
// CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'f'
// CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-F-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
// CHECK-F-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
// CHECK-F-NEXT: <RefType abbrevid=6 op0=1/>
// CHECK-F-NEXT: <Field abbrevid=7 op0=1/>
// CHECK-F-NEXT: </ReferenceBlock>
// CHECK-F-NEXT: <DefLocation abbrevid=6 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}'
// CHECK-F-NEXT: <Location abbrevid=7 op0=18 op1={{[0-9]*}}/> blob data = '{{.*}}'
// CHECK-F-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-F-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-F-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
// CHECK-F-NEXT: <Field abbrevid=7 op0=4/>
// CHECK-F-NEXT: </ReferenceBlock>
// CHECK-F-NEXT: </TypeBlock>
// CHECK-F-NEXT: </FunctionBlock>

namespace B {
// CHECK-B: <NamespaceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-B-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
// CHECK-B-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
// CHECK-B-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-B-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
// CHECK-B-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
// CHECK-B-NEXT: <RefType abbrevid=6 op0=1/>
// CHECK-B-NEXT: <Field abbrevid=7 op0=1/>
// CHECK-B-NEXT: </ReferenceBlock>
// CHECK-B-NEXT: </NamespaceBlock>

enum E { X };
// CHECK-E: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=233 op2=171 op3=247 op4=231 op5=226 op6=66 op7=91 op8=98 op9=103 op10=35 op11=212 op12=30 op13=118 op14=228 op15=188 op16=126 op17=122 op18=91 op19=215 op20=117/>
// CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
// CHECK-E-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
// CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
// CHECK-E-NEXT: <RefType abbrevid=6 op0=1/>
// CHECK-E-NEXT: <Field abbrevid=7 op0=1/>
// CHECK-E-NEXT: </ReferenceBlock>
// CHECK-E-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-E-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
// CHECK-E-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
// CHECK-E-NEXT: <RefType abbrevid=6 op0=1/>
// CHECK-E-NEXT: <Field abbrevid=7 op0=1/>
// CHECK-E-NEXT: </ReferenceBlock>
// CHECK-E-NEXT: <DefLocation abbrevid=6 op0=56 op1={{[0-9]*}}/> blob data = '{{.*}}'
// CHECK-E-NEXT: <Member abbrevid=8 op0=1/> blob data = 'X'
// CHECK-E-NEXT: </EnumBlock>

E func(int i) { return X; }
// CHECK-FUNC: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-FUNC-NEXT: <USR abbrevid=4 op0=20 op1=154 op2=130 op3=203 op4=51 op5=237 op6=15 op7=223 op8=129 op9=238 op10=56 op11=61 op12=49 op13=205 op14=9 op15=87 op16=209 op17=83 op18=197 op19=232 op20=64/>
// CHECK-FUNC-NEXT: <Name abbrevid=5 op0=4/> blob data = 'func'
// CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-FUNC-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
// CHECK-FUNC-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
// CHECK-FUNC-NEXT: <RefType abbrevid=6 op0=1/>
// CHECK-FUNC-NEXT: <Field abbrevid=7 op0=1/>
// CHECK-FUNC-NEXT: </ReferenceBlock>
// CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-FUNC-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
// CHECK-FUNC-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
// CHECK-FUNC-NEXT: <RefType abbrevid=6 op0=1/>
// CHECK-FUNC-NEXT: <Field abbrevid=7 op0=1/>
// CHECK-FUNC-NEXT: </ReferenceBlock>
// CHECK-FUNC-NEXT: <DefLocation abbrevid=6 op0=76 op1={{[0-9]*}}/> blob data = '{{.*}}'
// CHECK-FUNC-NEXT: <TypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-FUNC-NEXT: <Name abbrevid=5 op0=12/> blob data = 'enum A::B::E'
// CHECK-FUNC-NEXT: <Field abbrevid=7 op0=4/>
// CHECK-FUNC-NEXT: </ReferenceBlock>
// CHECK-FUNC-NEXT: </TypeBlock>
// CHECK-FUNC-NEXT: <FieldTypeBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-FUNC-NEXT: <ReferenceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
// CHECK-FUNC-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
// CHECK-FUNC-NEXT: <Field abbrevid=7 op0=4/>
// CHECK-FUNC-NEXT: </ReferenceBlock>
// CHECK-FUNC-NEXT: <Name abbrevid=4 op0=1/> blob data = 'i'
// CHECK-FUNC-NEXT: </FieldTypeBlock>
// CHECK-FUNC-NEXT: </FunctionBlock>

} // namespace B
} // namespace A
254 changes: 254 additions & 0 deletions clang-tools-extra/test/clang-doc/bc-record.cpp

Large diffs are not rendered by default.