[clang-doc] Add html links to references
<a> tags are added for the parents and members of records and return type and params of functions. The link redirects to the reference's info file. The directory path where each info file will be saved is now generated in the serialization phase and stored as an attribute in each Info. Bitcode writer and reader were modified to handle the new attributes. Committed on behalf of Diego Astiazarán (diegoaat97@gmail.com). Differential Revision: https://reviews.llvm.org/D63663 llvm-svn: 365937
This commit is contained in:
parent
13f7ddff17
commit
2c1c9a2407
|
@ -148,6 +148,8 @@ llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
||||||
return decodeRecord(R, I->USR, Blob);
|
return decodeRecord(R, I->USR, Blob);
|
||||||
case NAMESPACE_NAME:
|
case NAMESPACE_NAME:
|
||||||
return decodeRecord(R, I->Name, Blob);
|
return decodeRecord(R, I->Name, Blob);
|
||||||
|
case NAMESPACE_PATH:
|
||||||
|
return decodeRecord(R, I->Path, Blob);
|
||||||
default:
|
default:
|
||||||
return llvm::make_error<llvm::StringError>(
|
return llvm::make_error<llvm::StringError>(
|
||||||
"Invalid field for NamespaceInfo.\n", llvm::inconvertibleErrorCode());
|
"Invalid field for NamespaceInfo.\n", llvm::inconvertibleErrorCode());
|
||||||
|
@ -161,6 +163,8 @@ llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
||||||
return decodeRecord(R, I->USR, Blob);
|
return decodeRecord(R, I->USR, Blob);
|
||||||
case RECORD_NAME:
|
case RECORD_NAME:
|
||||||
return decodeRecord(R, I->Name, Blob);
|
return decodeRecord(R, I->Name, Blob);
|
||||||
|
case RECORD_PATH:
|
||||||
|
return decodeRecord(R, I->Path, Blob);
|
||||||
case RECORD_DEFLOCATION:
|
case RECORD_DEFLOCATION:
|
||||||
return decodeRecord(R, I->DefLoc, Blob);
|
return decodeRecord(R, I->DefLoc, Blob);
|
||||||
case RECORD_LOCATION:
|
case RECORD_LOCATION:
|
||||||
|
@ -286,6 +290,8 @@ llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
|
||||||
return decodeRecord(R, I->Name, Blob);
|
return decodeRecord(R, I->Name, Blob);
|
||||||
case REFERENCE_TYPE:
|
case REFERENCE_TYPE:
|
||||||
return decodeRecord(R, I->RefType, Blob);
|
return decodeRecord(R, I->RefType, Blob);
|
||||||
|
case REFERENCE_PATH:
|
||||||
|
return decodeRecord(R, I->Path, Blob);
|
||||||
case REFERENCE_FIELD:
|
case REFERENCE_FIELD:
|
||||||
return decodeRecord(R, F, Blob);
|
return decodeRecord(R, F, Blob);
|
||||||
default:
|
default:
|
||||||
|
@ -685,7 +691,7 @@ ClangDocBitcodeReader::createInfo(unsigned ID) {
|
||||||
std::unique_ptr<Info> I = llvm::make_unique<T>();
|
std::unique_ptr<Info> I = llvm::make_unique<T>();
|
||||||
if (auto Err = readBlock(ID, static_cast<T *>(I.get())))
|
if (auto Err = readBlock(ID, static_cast<T *>(I.get())))
|
||||||
return std::move(Err);
|
return std::move(Err);
|
||||||
return std::unique_ptr<Info>{std::move(I)};;
|
return std::unique_ptr<Info>{std::move(I)};
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Expected<std::unique_ptr<Info>>
|
llvm::Expected<std::unique_ptr<Info>>
|
||||||
|
|
|
@ -148,6 +148,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
|
||||||
{MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
|
{MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
|
||||||
{NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
|
{NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
|
||||||
{NAMESPACE_NAME, {"Name", &StringAbbrev}},
|
{NAMESPACE_NAME, {"Name", &StringAbbrev}},
|
||||||
|
{NAMESPACE_PATH, {"Path", &StringAbbrev}},
|
||||||
{ENUM_USR, {"USR", &SymbolIDAbbrev}},
|
{ENUM_USR, {"USR", &SymbolIDAbbrev}},
|
||||||
{ENUM_NAME, {"Name", &StringAbbrev}},
|
{ENUM_NAME, {"Name", &StringAbbrev}},
|
||||||
{ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
|
{ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
|
||||||
|
@ -156,6 +157,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
|
||||||
{ENUM_SCOPED, {"Scoped", &BoolAbbrev}},
|
{ENUM_SCOPED, {"Scoped", &BoolAbbrev}},
|
||||||
{RECORD_USR, {"USR", &SymbolIDAbbrev}},
|
{RECORD_USR, {"USR", &SymbolIDAbbrev}},
|
||||||
{RECORD_NAME, {"Name", &StringAbbrev}},
|
{RECORD_NAME, {"Name", &StringAbbrev}},
|
||||||
|
{RECORD_PATH, {"Path", &StringAbbrev}},
|
||||||
{RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
|
{RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
|
||||||
{RECORD_LOCATION, {"Location", &LocationAbbrev}},
|
{RECORD_LOCATION, {"Location", &LocationAbbrev}},
|
||||||
{RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
|
{RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
|
||||||
|
@ -169,6 +171,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
|
||||||
{REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
|
{REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
|
||||||
{REFERENCE_NAME, {"Name", &StringAbbrev}},
|
{REFERENCE_NAME, {"Name", &StringAbbrev}},
|
||||||
{REFERENCE_TYPE, {"RefType", &IntAbbrev}},
|
{REFERENCE_TYPE, {"RefType", &IntAbbrev}},
|
||||||
|
{REFERENCE_PATH, {"Path", &StringAbbrev}},
|
||||||
{REFERENCE_FIELD, {"Field", &IntAbbrev}}};
|
{REFERENCE_FIELD, {"Field", &IntAbbrev}}};
|
||||||
assert(Inits.size() == RecordIdCount);
|
assert(Inits.size() == RecordIdCount);
|
||||||
for (const auto &Init : Inits) {
|
for (const auto &Init : Inits) {
|
||||||
|
@ -199,18 +202,20 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
|
||||||
{ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_MEMBER,
|
{ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_MEMBER,
|
||||||
ENUM_SCOPED}},
|
ENUM_SCOPED}},
|
||||||
// Namespace Block
|
// Namespace Block
|
||||||
{BI_NAMESPACE_BLOCK_ID, {NAMESPACE_USR, NAMESPACE_NAME}},
|
{BI_NAMESPACE_BLOCK_ID,
|
||||||
|
{NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},
|
||||||
// Record Block
|
// Record Block
|
||||||
{BI_RECORD_BLOCK_ID,
|
{BI_RECORD_BLOCK_ID,
|
||||||
{RECORD_USR, RECORD_NAME, RECORD_DEFLOCATION, RECORD_LOCATION,
|
{RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,
|
||||||
RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},
|
RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},
|
||||||
// Function Block
|
// Function Block
|
||||||
{BI_FUNCTION_BLOCK_ID,
|
{BI_FUNCTION_BLOCK_ID,
|
||||||
{FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
|
{FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
|
||||||
FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
|
FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
|
||||||
// Reference Block
|
// Reference Block
|
||||||
{BI_REFERENCE_BLOCK_ID,
|
{BI_REFERENCE_BLOCK_ID,
|
||||||
{REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_FIELD}}};
|
{REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_PATH,
|
||||||
|
REFERENCE_FIELD}}};
|
||||||
|
|
||||||
// AbbreviationMap
|
// AbbreviationMap
|
||||||
|
|
||||||
|
@ -381,6 +386,7 @@ void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {
|
||||||
emitRecord(R.USR, REFERENCE_USR);
|
emitRecord(R.USR, REFERENCE_USR);
|
||||||
emitRecord(R.Name, REFERENCE_NAME);
|
emitRecord(R.Name, REFERENCE_NAME);
|
||||||
emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
|
emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
|
||||||
|
emitRecord(R.Path, REFERENCE_PATH);
|
||||||
emitRecord((unsigned)Field, REFERENCE_FIELD);
|
emitRecord((unsigned)Field, REFERENCE_FIELD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,6 +434,7 @@ void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
|
||||||
StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
|
StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
|
||||||
emitRecord(I.USR, NAMESPACE_USR);
|
emitRecord(I.USR, NAMESPACE_USR);
|
||||||
emitRecord(I.Name, NAMESPACE_NAME);
|
emitRecord(I.Name, NAMESPACE_NAME);
|
||||||
|
emitRecord(I.Path, NAMESPACE_PATH);
|
||||||
for (const auto &N : I.Namespace)
|
for (const auto &N : I.Namespace)
|
||||||
emitBlock(N, FieldId::F_namespace);
|
emitBlock(N, FieldId::F_namespace);
|
||||||
for (const auto &CI : I.Description)
|
for (const auto &CI : I.Description)
|
||||||
|
@ -463,6 +470,7 @@ void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
|
||||||
StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
|
StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
|
||||||
emitRecord(I.USR, RECORD_USR);
|
emitRecord(I.USR, RECORD_USR);
|
||||||
emitRecord(I.Name, RECORD_NAME);
|
emitRecord(I.Name, RECORD_NAME);
|
||||||
|
emitRecord(I.Path, RECORD_PATH);
|
||||||
for (const auto &N : I.Namespace)
|
for (const auto &N : I.Namespace)
|
||||||
emitBlock(N, FieldId::F_namespace);
|
emitBlock(N, FieldId::F_namespace);
|
||||||
for (const auto &CI : I.Description)
|
for (const auto &CI : I.Description)
|
||||||
|
|
|
@ -91,6 +91,7 @@ enum RecordId {
|
||||||
MEMBER_TYPE_ACCESS,
|
MEMBER_TYPE_ACCESS,
|
||||||
NAMESPACE_USR,
|
NAMESPACE_USR,
|
||||||
NAMESPACE_NAME,
|
NAMESPACE_NAME,
|
||||||
|
NAMESPACE_PATH,
|
||||||
ENUM_USR,
|
ENUM_USR,
|
||||||
ENUM_NAME,
|
ENUM_NAME,
|
||||||
ENUM_DEFLOCATION,
|
ENUM_DEFLOCATION,
|
||||||
|
@ -99,6 +100,7 @@ enum RecordId {
|
||||||
ENUM_SCOPED,
|
ENUM_SCOPED,
|
||||||
RECORD_USR,
|
RECORD_USR,
|
||||||
RECORD_NAME,
|
RECORD_NAME,
|
||||||
|
RECORD_PATH,
|
||||||
RECORD_DEFLOCATION,
|
RECORD_DEFLOCATION,
|
||||||
RECORD_LOCATION,
|
RECORD_LOCATION,
|
||||||
RECORD_TAG_TYPE,
|
RECORD_TAG_TYPE,
|
||||||
|
@ -106,6 +108,7 @@ enum RecordId {
|
||||||
REFERENCE_USR,
|
REFERENCE_USR,
|
||||||
REFERENCE_NAME,
|
REFERENCE_NAME,
|
||||||
REFERENCE_TYPE,
|
REFERENCE_TYPE,
|
||||||
|
REFERENCE_PATH,
|
||||||
REFERENCE_FIELD,
|
REFERENCE_FIELD,
|
||||||
RI_LAST,
|
RI_LAST,
|
||||||
RI_FIRST = VERSION
|
RI_FIRST = VERSION
|
||||||
|
|
|
@ -57,19 +57,6 @@ std::string getTagType(TagTypeKind AS) {
|
||||||
llvm_unreachable("Unknown TagTypeKind");
|
llvm_unreachable("Unknown TagTypeKind");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a comma-separated list of Refs
|
|
||||||
// Used to display the parents of a record
|
|
||||||
std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
|
|
||||||
std::string Buffer;
|
|
||||||
llvm::raw_string_ostream Stream(Buffer);
|
|
||||||
for (const auto &R : Refs) {
|
|
||||||
if (&R != Refs.begin())
|
|
||||||
Stream << ", ";
|
|
||||||
Stream << R.Name;
|
|
||||||
}
|
|
||||||
return Stream.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// This anchor is used to force the linker to link in the generated object file
|
// This anchor is used to force the linker to link in the generated object file
|
||||||
// and thus register the generators.
|
// and thus register the generators.
|
||||||
extern volatile int YAMLGeneratorAnchorSource;
|
extern volatile int YAMLGeneratorAnchorSource;
|
||||||
|
|
|
@ -38,8 +38,6 @@ std::string getAccess(AccessSpecifier AS);
|
||||||
|
|
||||||
std::string getTagType(TagTypeKind AS);
|
std::string getTagType(TagTypeKind AS);
|
||||||
|
|
||||||
std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs);
|
|
||||||
|
|
||||||
} // namespace doc
|
} // namespace doc
|
||||||
} // namespace clang
|
} // namespace clang
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,6 @@ using namespace llvm;
|
||||||
namespace clang {
|
namespace clang {
|
||||||
namespace doc {
|
namespace doc {
|
||||||
|
|
||||||
template <typename Derived, typename Base,
|
|
||||||
typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
|
|
||||||
static void AppendVector(std::vector<Derived> &&New,
|
|
||||||
std::vector<Base> &Original) {
|
|
||||||
std::move(New.begin(), New.end(), std::back_inserter(Original));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class HTMLTag {
|
class HTMLTag {
|
||||||
|
@ -40,6 +33,7 @@ public:
|
||||||
TAG_P,
|
TAG_P,
|
||||||
TAG_UL,
|
TAG_UL,
|
||||||
TAG_LI,
|
TAG_LI,
|
||||||
|
TAG_A,
|
||||||
};
|
};
|
||||||
|
|
||||||
HTMLTag() = default;
|
HTMLTag() = default;
|
||||||
|
@ -58,15 +52,22 @@ private:
|
||||||
TagType Value;
|
TagType Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum NodeType {
|
||||||
|
NODE_TEXT,
|
||||||
|
NODE_TAG,
|
||||||
|
};
|
||||||
|
|
||||||
struct HTMLNode {
|
struct HTMLNode {
|
||||||
|
HTMLNode(NodeType Type) : Type(Type) {}
|
||||||
virtual ~HTMLNode() = default;
|
virtual ~HTMLNode() = default;
|
||||||
|
|
||||||
virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0;
|
virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0;
|
||||||
|
NodeType Type; // Type of node
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextNode : public HTMLNode {
|
struct TextNode : public HTMLNode {
|
||||||
TextNode(llvm::StringRef Text, bool Indented)
|
TextNode(const Twine &Text, bool Indented = true)
|
||||||
: Text(Text), Indented(Indented) {}
|
: HTMLNode(NodeType::NODE_TEXT), Text(Text.str()), Indented(Indented) {}
|
||||||
|
|
||||||
std::string Text; // Content of node
|
std::string Text; // Content of node
|
||||||
bool Indented; // Indicates if an indentation must be rendered before the text
|
bool Indented; // Indicates if an indentation must be rendered before the text
|
||||||
|
@ -75,7 +76,8 @@ struct TextNode : public HTMLNode {
|
||||||
|
|
||||||
struct TagNode : public HTMLNode {
|
struct TagNode : public HTMLNode {
|
||||||
TagNode(HTMLTag Tag)
|
TagNode(HTMLTag Tag)
|
||||||
: Tag(Tag), InlineChildren(Tag.HasInlineChildren()),
|
: HTMLNode(NodeType::NODE_TAG), Tag(Tag),
|
||||||
|
InlineChildren(Tag.HasInlineChildren()),
|
||||||
SelfClosing(Tag.IsSelfClosing()) {}
|
SelfClosing(Tag.IsSelfClosing()) {}
|
||||||
TagNode(HTMLTag Tag, const Twine &Text) : TagNode(Tag) {
|
TagNode(HTMLTag Tag, const Twine &Text) : TagNode(Tag) {
|
||||||
Children.emplace_back(
|
Children.emplace_back(
|
||||||
|
@ -121,6 +123,7 @@ bool HTMLTag::IsSelfClosing() const {
|
||||||
case HTMLTag::TAG_P:
|
case HTMLTag::TAG_P:
|
||||||
case HTMLTag::TAG_UL:
|
case HTMLTag::TAG_UL:
|
||||||
case HTMLTag::TAG_LI:
|
case HTMLTag::TAG_LI:
|
||||||
|
case HTMLTag::TAG_A:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
llvm_unreachable("Unhandled HTMLTag::TagType");
|
llvm_unreachable("Unhandled HTMLTag::TagType");
|
||||||
|
@ -134,6 +137,7 @@ bool HTMLTag::HasInlineChildren() const {
|
||||||
case HTMLTag::TAG_H2:
|
case HTMLTag::TAG_H2:
|
||||||
case HTMLTag::TAG_H3:
|
case HTMLTag::TAG_H3:
|
||||||
case HTMLTag::TAG_LI:
|
case HTMLTag::TAG_LI:
|
||||||
|
case HTMLTag::TAG_A:
|
||||||
return true;
|
return true;
|
||||||
case HTMLTag::TAG_DIV:
|
case HTMLTag::TAG_DIV:
|
||||||
case HTMLTag::TAG_P:
|
case HTMLTag::TAG_P:
|
||||||
|
@ -163,6 +167,8 @@ llvm::SmallString<16> HTMLTag::ToString() const {
|
||||||
return llvm::SmallString<16>("ul");
|
return llvm::SmallString<16>("ul");
|
||||||
case HTMLTag::TAG_LI:
|
case HTMLTag::TAG_LI:
|
||||||
return llvm::SmallString<16>("li");
|
return llvm::SmallString<16>("li");
|
||||||
|
case HTMLTag::TAG_A:
|
||||||
|
return llvm::SmallString<16>("a");
|
||||||
}
|
}
|
||||||
llvm_unreachable("Unhandled HTMLTag::TagType");
|
llvm_unreachable("Unhandled HTMLTag::TagType");
|
||||||
}
|
}
|
||||||
|
@ -185,21 +191,87 @@ void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
|
||||||
OS << ">";
|
OS << ">";
|
||||||
if (!InlineChildren)
|
if (!InlineChildren)
|
||||||
OS << "\n";
|
OS << "\n";
|
||||||
int ChildrenIndentation = InlineChildren ? 0 : IndentationLevel + 1;
|
bool NewLineRendered = true;
|
||||||
for (const auto &C : Children) {
|
for (const auto &C : Children) {
|
||||||
|
int ChildrenIndentation =
|
||||||
|
InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;
|
||||||
C->Render(OS, ChildrenIndentation);
|
C->Render(OS, ChildrenIndentation);
|
||||||
if (!InlineChildren)
|
if (!InlineChildren && (C == Children.back() ||
|
||||||
|
(C->Type != NodeType::NODE_TEXT ||
|
||||||
|
(&C + 1)->get()->Type != NodeType::NODE_TEXT))) {
|
||||||
OS << "\n";
|
OS << "\n";
|
||||||
|
NewLineRendered = true;
|
||||||
|
} else
|
||||||
|
NewLineRendered = false;
|
||||||
}
|
}
|
||||||
if (!InlineChildren)
|
if (!InlineChildren)
|
||||||
OS.indent(IndentationLevel * 2);
|
OS.indent(IndentationLevel * 2);
|
||||||
OS << "</" << Tag.ToString() << ">";
|
OS << "</" << Tag.ToString() << ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Derived, typename Base,
|
||||||
|
typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
|
||||||
|
static void AppendVector(std::vector<Derived> &&New,
|
||||||
|
std::vector<Base> &Original) {
|
||||||
|
std::move(New.begin(), New.end(), std::back_inserter(Original));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the relative path that names the file path relative to the given
|
||||||
|
// directory.
|
||||||
|
static SmallString<128> computeRelativePath(StringRef FilePath,
|
||||||
|
StringRef Directory) {
|
||||||
|
StringRef Path = FilePath;
|
||||||
|
while (!Path.empty()) {
|
||||||
|
if (Directory == Path)
|
||||||
|
return FilePath.substr(Path.size());
|
||||||
|
Path = llvm::sys::path::parent_path(Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef Dir = Directory;
|
||||||
|
SmallString<128> Result;
|
||||||
|
while (!Dir.empty()) {
|
||||||
|
if (Dir == FilePath)
|
||||||
|
break;
|
||||||
|
Dir = llvm::sys::path::parent_path(Dir);
|
||||||
|
llvm::sys::path::append(Result, "..");
|
||||||
|
}
|
||||||
|
llvm::sys::path::append(Result, FilePath.substr(Dir.size()));
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
// HTML generation
|
// HTML generation
|
||||||
|
|
||||||
|
static std::unique_ptr<TagNode> genLink(const Twine &Text, const Twine &Link) {
|
||||||
|
auto LinkNode = llvm::make_unique<TagNode>(HTMLTag::TAG_A, Text);
|
||||||
|
LinkNode->Attributes.try_emplace("href", Link.str());
|
||||||
|
return LinkNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<HTMLNode> genTypeReference(const Reference &Type,
|
||||||
|
StringRef CurrentDirectory) {
|
||||||
|
if (Type.Path.empty())
|
||||||
|
return llvm::make_unique<TextNode>(Type.Name);
|
||||||
|
llvm::SmallString<128> Path =
|
||||||
|
computeRelativePath(Type.Path, CurrentDirectory);
|
||||||
|
llvm::sys::path::append(Path, Type.Name + ".html");
|
||||||
|
return genLink(Type.Name, Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::unique_ptr<HTMLNode>>
|
||||||
|
genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs,
|
||||||
|
const StringRef &CurrentDirectory) {
|
||||||
|
std::vector<std::unique_ptr<HTMLNode>> Out;
|
||||||
|
for (const auto &R : Refs) {
|
||||||
|
if (&R != Refs.begin())
|
||||||
|
Out.emplace_back(llvm::make_unique<TextNode>(", "));
|
||||||
|
Out.emplace_back(genTypeReference(R, CurrentDirectory));
|
||||||
|
}
|
||||||
|
return Out;
|
||||||
|
}
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I);
|
static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I);
|
||||||
static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I);
|
static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
|
||||||
|
StringRef ParentInfoDir);
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<TagNode>>
|
static std::vector<std::unique_ptr<TagNode>>
|
||||||
genEnumsBlock(const std::vector<EnumInfo> &Enums) {
|
genEnumsBlock(const std::vector<EnumInfo> &Enums) {
|
||||||
|
@ -229,7 +301,8 @@ genEnumMembersBlock(const llvm::SmallVector<SmallString<16>, 4> &Members) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<TagNode>>
|
static std::vector<std::unique_ptr<TagNode>>
|
||||||
genFunctionsBlock(const std::vector<FunctionInfo> &Functions) {
|
genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
|
||||||
|
StringRef ParentInfoDir) {
|
||||||
if (Functions.empty())
|
if (Functions.empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -238,14 +311,15 @@ genFunctionsBlock(const std::vector<FunctionInfo> &Functions) {
|
||||||
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
|
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
|
||||||
auto &DivBody = Out.back();
|
auto &DivBody = Out.back();
|
||||||
for (const auto &F : Functions) {
|
for (const auto &F : Functions) {
|
||||||
std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F);
|
std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F, ParentInfoDir);
|
||||||
AppendVector(std::move(Nodes), DivBody->Children);
|
AppendVector(std::move(Nodes), DivBody->Children);
|
||||||
}
|
}
|
||||||
return Out;
|
return Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<TagNode>>
|
static std::vector<std::unique_ptr<TagNode>>
|
||||||
genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members) {
|
genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members,
|
||||||
|
StringRef ParentInfoDir) {
|
||||||
if (Members.empty())
|
if (Members.empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -257,8 +331,11 @@ genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members) {
|
||||||
std::string Access = getAccess(M.Access);
|
std::string Access = getAccess(M.Access);
|
||||||
if (Access != "")
|
if (Access != "")
|
||||||
Access = Access + " ";
|
Access = Access + " ";
|
||||||
ULBody->Children.emplace_back(llvm::make_unique<TagNode>(
|
auto LIBody = llvm::make_unique<TagNode>(HTMLTag::TAG_LI);
|
||||||
HTMLTag::TAG_LI, Access + M.Type.Name + " " + M.Name));
|
LIBody->Children.emplace_back(llvm::make_unique<TextNode>(Access));
|
||||||
|
LIBody->Children.emplace_back(genTypeReference(M.Type, ParentInfoDir));
|
||||||
|
LIBody->Children.emplace_back(llvm::make_unique<TextNode>(" " + M.Name));
|
||||||
|
ULBody->Children.emplace_back(std::move(LIBody));
|
||||||
}
|
}
|
||||||
return Out;
|
return Out;
|
||||||
}
|
}
|
||||||
|
@ -346,25 +423,35 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I) {
|
||||||
return Out;
|
return Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I) {
|
static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
|
||||||
|
StringRef ParentInfoDir) {
|
||||||
std::vector<std::unique_ptr<TagNode>> Out;
|
std::vector<std::unique_ptr<TagNode>> Out;
|
||||||
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
|
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
|
||||||
|
|
||||||
std::string Buffer;
|
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
|
||||||
llvm::raw_string_ostream Stream(Buffer);
|
auto &FunctionHeader = Out.back();
|
||||||
for (const auto &P : I.Params) {
|
|
||||||
if (&P != I.Params.begin())
|
|
||||||
Stream << ", ";
|
|
||||||
Stream << P.Type.Name + " " + P.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Access = getAccess(I.Access);
|
std::string Access = getAccess(I.Access);
|
||||||
if (Access != "")
|
if (Access != "")
|
||||||
Access = Access + " ";
|
FunctionHeader->Children.emplace_back(
|
||||||
|
llvm::make_unique<TextNode>(Access + " "));
|
||||||
|
if (I.ReturnType.Type.Name != "") {
|
||||||
|
FunctionHeader->Children.emplace_back(
|
||||||
|
genTypeReference(I.ReturnType.Type, ParentInfoDir));
|
||||||
|
FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(" "));
|
||||||
|
}
|
||||||
|
FunctionHeader->Children.emplace_back(
|
||||||
|
llvm::make_unique<TextNode>(I.Name + "("));
|
||||||
|
|
||||||
Out.emplace_back(llvm::make_unique<TagNode>(
|
for (const auto &P : I.Params) {
|
||||||
HTMLTag::TAG_P, Access + I.ReturnType.Type.Name + " " + I.Name + "(" +
|
if (&P != I.Params.begin())
|
||||||
Stream.str() + ")"));
|
FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(", "));
|
||||||
|
FunctionHeader->Children.emplace_back(
|
||||||
|
genTypeReference(P.Type, ParentInfoDir));
|
||||||
|
FunctionHeader->Children.emplace_back(
|
||||||
|
llvm::make_unique<TextNode>(" " + P.Name));
|
||||||
|
}
|
||||||
|
FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(")"));
|
||||||
|
|
||||||
if (I.DefLoc)
|
if (I.DefLoc)
|
||||||
Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
|
Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
|
||||||
|
@ -398,7 +485,7 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const NamespaceInfo &I,
|
||||||
AppendVector(std::move(ChildRecords), Out);
|
AppendVector(std::move(ChildRecords), Out);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<TagNode>> ChildFunctions =
|
std::vector<std::unique_ptr<TagNode>> ChildFunctions =
|
||||||
genFunctionsBlock(I.ChildFunctions);
|
genFunctionsBlock(I.ChildFunctions, I.Path);
|
||||||
AppendVector(std::move(ChildFunctions), Out);
|
AppendVector(std::move(ChildFunctions), Out);
|
||||||
std::vector<std::unique_ptr<TagNode>> ChildEnums =
|
std::vector<std::unique_ptr<TagNode>> ChildEnums =
|
||||||
genEnumsBlock(I.ChildEnums);
|
genEnumsBlock(I.ChildEnums);
|
||||||
|
@ -420,29 +507,34 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const RecordInfo &I,
|
||||||
if (!I.Description.empty())
|
if (!I.Description.empty())
|
||||||
Out.emplace_back(genHTML(I.Description));
|
Out.emplace_back(genHTML(I.Description));
|
||||||
|
|
||||||
std::string Parents = genReferenceList(I.Parents);
|
std::vector<std::unique_ptr<HTMLNode>> Parents =
|
||||||
std::string VParents = genReferenceList(I.VirtualParents);
|
genReferenceList(I.Parents, I.Path);
|
||||||
|
std::vector<std::unique_ptr<HTMLNode>> VParents =
|
||||||
|
genReferenceList(I.VirtualParents, I.Path);
|
||||||
if (!Parents.empty() || !VParents.empty()) {
|
if (!Parents.empty() || !VParents.empty()) {
|
||||||
|
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
|
||||||
|
auto &PBody = Out.back();
|
||||||
|
PBody->Children.emplace_back(llvm::make_unique<TextNode>("Inherits from "));
|
||||||
if (Parents.empty())
|
if (Parents.empty())
|
||||||
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P,
|
AppendVector(std::move(VParents), PBody->Children);
|
||||||
"Inherits from " + VParents));
|
|
||||||
else if (VParents.empty())
|
else if (VParents.empty())
|
||||||
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P,
|
AppendVector(std::move(Parents), PBody->Children);
|
||||||
"Inherits from " + Parents));
|
else {
|
||||||
else
|
AppendVector(std::move(Parents), PBody->Children);
|
||||||
Out.emplace_back(llvm::make_unique<TagNode>(
|
PBody->Children.emplace_back(llvm::make_unique<TextNode>(", "));
|
||||||
HTMLTag::TAG_P, "Inherits from " + Parents + ", " + VParents));
|
AppendVector(std::move(VParents), PBody->Children);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<TagNode>> Members =
|
std::vector<std::unique_ptr<TagNode>> Members =
|
||||||
genRecordMembersBlock(I.Members);
|
genRecordMembersBlock(I.Members, I.Path);
|
||||||
AppendVector(std::move(Members), Out);
|
AppendVector(std::move(Members), Out);
|
||||||
std::vector<std::unique_ptr<TagNode>> ChildRecords =
|
std::vector<std::unique_ptr<TagNode>> ChildRecords =
|
||||||
genReferencesBlock(I.ChildRecords, "Records");
|
genReferencesBlock(I.ChildRecords, "Records");
|
||||||
AppendVector(std::move(ChildRecords), Out);
|
AppendVector(std::move(ChildRecords), Out);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<TagNode>> ChildFunctions =
|
std::vector<std::unique_ptr<TagNode>> ChildFunctions =
|
||||||
genFunctionsBlock(I.ChildFunctions);
|
genFunctionsBlock(I.ChildFunctions, I.Path);
|
||||||
AppendVector(std::move(ChildFunctions), Out);
|
AppendVector(std::move(ChildFunctions), Out);
|
||||||
std::vector<std::unique_ptr<TagNode>> ChildEnums =
|
std::vector<std::unique_ptr<TagNode>> ChildEnums =
|
||||||
genEnumsBlock(I.ChildEnums);
|
genEnumsBlock(I.ChildEnums);
|
||||||
|
@ -492,7 +584,7 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
|
||||||
}
|
}
|
||||||
case InfoType::IT_function: {
|
case InfoType::IT_function: {
|
||||||
std::vector<std::unique_ptr<TagNode>> Nodes =
|
std::vector<std::unique_ptr<TagNode>> Nodes =
|
||||||
genHTML(*static_cast<clang::doc::FunctionInfo *>(I));
|
genHTML(*static_cast<clang::doc::FunctionInfo *>(I), "");
|
||||||
AppendVector(std::move(Nodes), MainContentNode->Children);
|
AppendVector(std::move(Nodes), MainContentNode->Children);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,18 @@ static std::string genEmphasis(const Twine &Text) {
|
||||||
return "**" + Text.str() + "**";
|
return "**" + Text.str() + "**";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
|
||||||
|
std::string Buffer;
|
||||||
|
llvm::raw_string_ostream Stream(Buffer);
|
||||||
|
for (const auto &R : Refs) {
|
||||||
|
if (&R != Refs.begin())
|
||||||
|
Stream << ", ";
|
||||||
|
Stream << R.Name;
|
||||||
|
}
|
||||||
|
return Stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
static void writeLine(const Twine &Text, raw_ostream &OS) {
|
static void writeLine(const Twine &Text, raw_ostream &OS) {
|
||||||
OS << Text << "\n\n";
|
OS << Text << "\n\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,8 @@ void Info::mergeBase(Info &&Other) {
|
||||||
USR = Other.USR;
|
USR = Other.USR;
|
||||||
if (Name == "")
|
if (Name == "")
|
||||||
Name = Other.Name;
|
Name = Other.Name;
|
||||||
|
if (Path == "")
|
||||||
|
Path = Other.Path;
|
||||||
if (Namespace.empty())
|
if (Namespace.empty())
|
||||||
Namespace = std::move(Other.Namespace);
|
Namespace = std::move(Other.Namespace);
|
||||||
// Unconditionally extend the description, since each decl may have a comment.
|
// Unconditionally extend the description, since each decl may have a comment.
|
||||||
|
|
|
@ -114,8 +114,11 @@ struct CommentInfo {
|
||||||
struct Reference {
|
struct Reference {
|
||||||
Reference() = default;
|
Reference() = default;
|
||||||
Reference(llvm::StringRef Name) : Name(Name) {}
|
Reference(llvm::StringRef Name) : Name(Name) {}
|
||||||
|
Reference(llvm::StringRef Name, StringRef Path) : Name(Name), Path(Path) {}
|
||||||
Reference(SymbolID USR, StringRef Name, InfoType IT)
|
Reference(SymbolID USR, StringRef Name, InfoType IT)
|
||||||
: USR(USR), Name(Name), RefType(IT) {}
|
: USR(USR), Name(Name), RefType(IT) {}
|
||||||
|
Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)
|
||||||
|
: USR(USR), Name(Name), RefType(IT), Path(Path) {}
|
||||||
|
|
||||||
bool operator==(const Reference &Other) const {
|
bool operator==(const Reference &Other) const {
|
||||||
return std::tie(USR, Name, RefType) ==
|
return std::tie(USR, Name, RefType) ==
|
||||||
|
@ -127,6 +130,8 @@ struct Reference {
|
||||||
InfoType RefType = InfoType::IT_default; // Indicates the type of this
|
InfoType RefType = InfoType::IT_default; // Indicates the type of this
|
||||||
// Reference (namespace, record,
|
// Reference (namespace, record,
|
||||||
// function, enum, default).
|
// function, enum, default).
|
||||||
|
llvm::SmallString<128> Path; // Path of directory where the clang-doc
|
||||||
|
// generated file will be saved
|
||||||
};
|
};
|
||||||
|
|
||||||
// A base struct for TypeInfos
|
// A base struct for TypeInfos
|
||||||
|
@ -134,7 +139,10 @@ struct TypeInfo {
|
||||||
TypeInfo() = default;
|
TypeInfo() = default;
|
||||||
TypeInfo(SymbolID Type, StringRef Field, InfoType IT)
|
TypeInfo(SymbolID Type, StringRef Field, InfoType IT)
|
||||||
: Type(Type, Field, IT) {}
|
: Type(Type, Field, IT) {}
|
||||||
|
TypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path)
|
||||||
|
: Type(Type, Field, IT, Path) {}
|
||||||
TypeInfo(llvm::StringRef RefName) : Type(RefName) {}
|
TypeInfo(llvm::StringRef RefName) : Type(RefName) {}
|
||||||
|
TypeInfo(llvm::StringRef RefName, StringRef Path) : Type(RefName, Path) {}
|
||||||
|
|
||||||
bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
|
bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
|
||||||
|
|
||||||
|
@ -144,11 +152,13 @@ struct TypeInfo {
|
||||||
// Info for field types.
|
// Info for field types.
|
||||||
struct FieldTypeInfo : public TypeInfo {
|
struct FieldTypeInfo : public TypeInfo {
|
||||||
FieldTypeInfo() = default;
|
FieldTypeInfo() = default;
|
||||||
FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT,
|
FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,
|
||||||
llvm::StringRef Name)
|
llvm::StringRef Name)
|
||||||
: TypeInfo(Type, Field, IT), Name(Name) {}
|
: TypeInfo(Type, Field, IT, Path), Name(Name) {}
|
||||||
FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
|
FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
|
||||||
: TypeInfo(RefName), Name(Name) {}
|
: TypeInfo(RefName), Name(Name) {}
|
||||||
|
FieldTypeInfo(llvm::StringRef RefName, StringRef Path, llvm::StringRef Name)
|
||||||
|
: TypeInfo(RefName, Path), Name(Name) {}
|
||||||
|
|
||||||
bool operator==(const FieldTypeInfo &Other) const {
|
bool operator==(const FieldTypeInfo &Other) const {
|
||||||
return std::tie(Type, Name) == std::tie(Other.Type, Other.Name);
|
return std::tie(Type, Name) == std::tie(Other.Type, Other.Name);
|
||||||
|
@ -160,12 +170,15 @@ struct FieldTypeInfo : public TypeInfo {
|
||||||
// Info for member types.
|
// Info for member types.
|
||||||
struct MemberTypeInfo : public FieldTypeInfo {
|
struct MemberTypeInfo : public FieldTypeInfo {
|
||||||
MemberTypeInfo() = default;
|
MemberTypeInfo() = default;
|
||||||
MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT,
|
MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,
|
||||||
llvm::StringRef Name, AccessSpecifier Access)
|
llvm::StringRef Name, AccessSpecifier Access)
|
||||||
: FieldTypeInfo(Type, Field, IT, Name), Access(Access) {}
|
: FieldTypeInfo(Type, Field, IT, Path, Name), Access(Access) {}
|
||||||
MemberTypeInfo(llvm::StringRef RefName, llvm::StringRef Name,
|
MemberTypeInfo(llvm::StringRef RefName, llvm::StringRef Name,
|
||||||
AccessSpecifier Access)
|
AccessSpecifier Access)
|
||||||
: FieldTypeInfo(RefName, Name), Access(Access) {}
|
: FieldTypeInfo(RefName, Name), Access(Access) {}
|
||||||
|
MemberTypeInfo(llvm::StringRef RefName, StringRef Path, llvm::StringRef Name,
|
||||||
|
AccessSpecifier Access)
|
||||||
|
: FieldTypeInfo(RefName, Path, Name), Access(Access) {}
|
||||||
|
|
||||||
bool operator==(const MemberTypeInfo &Other) const {
|
bool operator==(const MemberTypeInfo &Other) const {
|
||||||
return std::tie(Type, Name, Access) ==
|
return std::tie(Type, Name, Access) ==
|
||||||
|
@ -220,6 +233,8 @@ struct Info {
|
||||||
llvm::SmallVector<Reference, 4>
|
llvm::SmallVector<Reference, 4>
|
||||||
Namespace; // List of parent namespaces for this decl.
|
Namespace; // List of parent namespaces for this decl.
|
||||||
std::vector<CommentInfo> Description; // Comment description of this decl.
|
std::vector<CommentInfo> Description; // Comment description of this decl.
|
||||||
|
llvm::SmallString<128> Path; // Path of directory where the clang-doc
|
||||||
|
// generated file will be saved
|
||||||
|
|
||||||
void mergeBase(Info &&I);
|
void mergeBase(Info &&I);
|
||||||
bool mergeable(const Info &Other);
|
bool mergeable(const Info &Other);
|
||||||
|
|
|
@ -24,6 +24,43 @@ SymbolID hashUSR(llvm::StringRef USR) {
|
||||||
return llvm::SHA1::hash(arrayRefFromStringRef(USR));
|
return llvm::SHA1::hash(arrayRefFromStringRef(USR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void
|
||||||
|
populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
|
||||||
|
const T *D, bool &IsAnonymousNamespace);
|
||||||
|
|
||||||
|
// A function to extract the appropriate relative path for a given info's
|
||||||
|
// documentation. The path returned is a composite of the parent namespaces.
|
||||||
|
//
|
||||||
|
// Example: Given the below, the diretory path for class C info will be
|
||||||
|
// <root>/A/B
|
||||||
|
//
|
||||||
|
// namespace A {
|
||||||
|
// namesapce B {
|
||||||
|
//
|
||||||
|
// class C {};
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
llvm::SmallString<128>
|
||||||
|
getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
|
||||||
|
std::error_code OK;
|
||||||
|
llvm::SmallString<128> Path;
|
||||||
|
for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
|
||||||
|
llvm::sys::path::append(Path, R->Name);
|
||||||
|
return Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::SmallString<128> getInfoRelativePath(const Decl *D) {
|
||||||
|
llvm::SmallVector<Reference, 4> Namespaces;
|
||||||
|
// The third arg in populateParentNamespaces is a boolean passed by reference,
|
||||||
|
// its value is not relevant in here so it's not used anywhere besides the
|
||||||
|
// function call
|
||||||
|
bool B = true;
|
||||||
|
populateParentNamespaces(Namespaces, D, B);
|
||||||
|
return getInfoRelativePath(Namespaces);
|
||||||
|
}
|
||||||
|
|
||||||
class ClangDocCommentVisitor
|
class ClangDocCommentVisitor
|
||||||
: public ConstCommentVisitor<ClangDocCommentVisitor> {
|
: public ConstCommentVisitor<ClangDocCommentVisitor> {
|
||||||
public:
|
public:
|
||||||
|
@ -203,13 +240,13 @@ static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) {
|
||||||
// valid, as opposed to an assert.
|
// valid, as opposed to an assert.
|
||||||
if (const auto *N = dyn_cast<EnumDecl>(T)) {
|
if (const auto *N = dyn_cast<EnumDecl>(T)) {
|
||||||
I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
|
I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
|
||||||
InfoType::IT_enum, F->getNameAsString(),
|
InfoType::IT_enum, getInfoRelativePath(N),
|
||||||
N->getAccessUnsafe());
|
F->getNameAsString(), N->getAccessUnsafe());
|
||||||
continue;
|
continue;
|
||||||
} else if (const auto *N = dyn_cast<RecordDecl>(T)) {
|
} else if (const auto *N = dyn_cast<RecordDecl>(T)) {
|
||||||
I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
|
I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
|
||||||
InfoType::IT_record, F->getNameAsString(),
|
InfoType::IT_record, getInfoRelativePath(N),
|
||||||
N->getAccessUnsafe());
|
F->getNameAsString(), N->getAccessUnsafe());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,11 +265,13 @@ static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
|
||||||
if (const auto *T = getDeclForType(P->getOriginalType())) {
|
if (const auto *T = getDeclForType(P->getOriginalType())) {
|
||||||
if (const auto *N = dyn_cast<EnumDecl>(T)) {
|
if (const auto *N = dyn_cast<EnumDecl>(T)) {
|
||||||
I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
|
I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
|
||||||
InfoType::IT_enum, P->getNameAsString());
|
InfoType::IT_enum, getInfoRelativePath(N),
|
||||||
|
P->getNameAsString());
|
||||||
continue;
|
continue;
|
||||||
} else if (const auto *N = dyn_cast<RecordDecl>(T)) {
|
} else if (const auto *N = dyn_cast<RecordDecl>(T)) {
|
||||||
I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
|
I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
|
||||||
InfoType::IT_record, P->getNameAsString());
|
InfoType::IT_record, getInfoRelativePath(N),
|
||||||
|
P->getNameAsString());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,14 +293,15 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
|
||||||
InfoType::IT_record);
|
InfoType::IT_record);
|
||||||
} else if (const RecordDecl *P = getDeclForType(B.getType()))
|
} else if (const RecordDecl *P = getDeclForType(B.getType()))
|
||||||
I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
|
I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
|
||||||
InfoType::IT_record);
|
InfoType::IT_record, getInfoRelativePath(P));
|
||||||
else
|
else
|
||||||
I.Parents.emplace_back(B.getType().getAsString());
|
I.Parents.emplace_back(B.getType().getAsString());
|
||||||
}
|
}
|
||||||
for (const CXXBaseSpecifier &B : D->vbases()) {
|
for (const CXXBaseSpecifier &B : D->vbases()) {
|
||||||
if (const auto *P = getDeclForType(B.getType()))
|
if (const auto *P = getDeclForType(B.getType()))
|
||||||
I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
|
I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
|
||||||
InfoType::IT_record);
|
InfoType::IT_record,
|
||||||
|
getInfoRelativePath(P));
|
||||||
else
|
else
|
||||||
I.VirtualParents.emplace_back(B.getType().getAsString());
|
I.VirtualParents.emplace_back(B.getType().getAsString());
|
||||||
}
|
}
|
||||||
|
@ -270,14 +310,14 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void
|
static void
|
||||||
populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
|
populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
|
||||||
const T *D, bool &IsAnonymousNamespace) {
|
const T *D, bool &IsInAnonymousNamespace) {
|
||||||
const auto *DC = dyn_cast<DeclContext>(D);
|
const auto *DC = dyn_cast<DeclContext>(D);
|
||||||
while ((DC = DC->getParent())) {
|
while ((DC = DC->getParent())) {
|
||||||
if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
|
if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
|
||||||
std::string Namespace;
|
std::string Namespace;
|
||||||
if (N->isAnonymousNamespace()) {
|
if (N->isAnonymousNamespace()) {
|
||||||
Namespace = "@nonymous_namespace";
|
Namespace = "@nonymous_namespace";
|
||||||
IsAnonymousNamespace = true;
|
IsInAnonymousNamespace = true;
|
||||||
} else
|
} else
|
||||||
Namespace = N->getNameAsString();
|
Namespace = N->getNameAsString();
|
||||||
Namespaces.emplace_back(getUSRForDecl(N), Namespace,
|
Namespaces.emplace_back(getUSRForDecl(N), Namespace,
|
||||||
|
@ -324,11 +364,11 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
|
||||||
populateSymbolInfo(I, D, FC, LineNumber, Filename, IsInAnonymousNamespace);
|
populateSymbolInfo(I, D, FC, LineNumber, Filename, IsInAnonymousNamespace);
|
||||||
if (const auto *T = getDeclForType(D->getReturnType())) {
|
if (const auto *T = getDeclForType(D->getReturnType())) {
|
||||||
if (dyn_cast<EnumDecl>(T))
|
if (dyn_cast<EnumDecl>(T))
|
||||||
I.ReturnType =
|
I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
|
||||||
TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum);
|
InfoType::IT_enum, getInfoRelativePath(T));
|
||||||
else if (dyn_cast<RecordDecl>(T))
|
else if (dyn_cast<RecordDecl>(T))
|
||||||
I.ReturnType =
|
I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
|
||||||
TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record);
|
InfoType::IT_record, getInfoRelativePath(T));
|
||||||
} else {
|
} else {
|
||||||
I.ReturnType = TypeInfo(D->getReturnType().getAsString());
|
I.ReturnType = TypeInfo(D->getReturnType().getAsString());
|
||||||
}
|
}
|
||||||
|
@ -347,16 +387,18 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
|
||||||
I->Name = D->isAnonymousNamespace()
|
I->Name = D->isAnonymousNamespace()
|
||||||
? llvm::SmallString<16>("@nonymous_namespace")
|
? llvm::SmallString<16>("@nonymous_namespace")
|
||||||
: I->Name;
|
: I->Name;
|
||||||
|
I->Path = getInfoRelativePath(I->Namespace);
|
||||||
if (I->Namespace.empty() && I->USR == SymbolID())
|
if (I->Namespace.empty() && I->USR == SymbolID())
|
||||||
return {std::unique_ptr<Info>{std::move(I)}, nullptr};
|
return {std::unique_ptr<Info>{std::move(I)}, nullptr};
|
||||||
|
|
||||||
SymbolID ParentUSR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;
|
auto ParentI = llvm::make_unique<NamespaceInfo>();
|
||||||
|
ParentI->USR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;
|
||||||
auto Parent = llvm::make_unique<NamespaceInfo>();
|
ParentI->ChildNamespaces.emplace_back(I->USR, I->Name,
|
||||||
Parent->USR = ParentUSR;
|
InfoType::IT_namespace);
|
||||||
Parent->ChildNamespaces.emplace_back(I->USR, I->Name, InfoType::IT_namespace);
|
if (I->Namespace.empty())
|
||||||
|
ParentI->Path = getInfoRelativePath(ParentI->Namespace);
|
||||||
return {std::unique_ptr<Info>{std::move(I)},
|
return {std::unique_ptr<Info>{std::move(I)},
|
||||||
std::unique_ptr<Info>{std::move(Parent)}};
|
std::unique_ptr<Info>{std::move(ParentI)}};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||||
|
@ -378,32 +420,34 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
|
||||||
}
|
}
|
||||||
parseBases(*I, C);
|
parseBases(*I, C);
|
||||||
}
|
}
|
||||||
|
I->Path = getInfoRelativePath(I->Namespace);
|
||||||
|
|
||||||
if (I->Namespace.empty()) {
|
if (I->Namespace.empty()) {
|
||||||
auto Parent = llvm::make_unique<NamespaceInfo>();
|
auto ParentI = llvm::make_unique<NamespaceInfo>();
|
||||||
Parent->USR = SymbolID();
|
ParentI->USR = SymbolID();
|
||||||
Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
|
ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
|
||||||
|
ParentI->Path = getInfoRelativePath(ParentI->Namespace);
|
||||||
return {std::unique_ptr<Info>{std::move(I)},
|
return {std::unique_ptr<Info>{std::move(I)},
|
||||||
std::unique_ptr<Info>{std::move(Parent)}};
|
std::unique_ptr<Info>{std::move(ParentI)}};
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (I->Namespace[0].RefType) {
|
switch (I->Namespace[0].RefType) {
|
||||||
case InfoType::IT_namespace: {
|
case InfoType::IT_namespace: {
|
||||||
auto Parent = llvm::make_unique<NamespaceInfo>();
|
auto ParentI = llvm::make_unique<NamespaceInfo>();
|
||||||
Parent->USR = I->Namespace[0].USR;
|
ParentI->USR = I->Namespace[0].USR;
|
||||||
Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
|
ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
|
||||||
return {std::unique_ptr<Info>{std::move(I)},
|
return {std::unique_ptr<Info>{std::move(I)},
|
||||||
std::unique_ptr<Info>{std::move(Parent)}};
|
std::unique_ptr<Info>{std::move(ParentI)}};
|
||||||
}
|
}
|
||||||
case InfoType::IT_record: {
|
case InfoType::IT_record: {
|
||||||
auto Parent = llvm::make_unique<RecordInfo>();
|
auto ParentI = llvm::make_unique<RecordInfo>();
|
||||||
Parent->USR = I->Namespace[0].USR;
|
ParentI->USR = I->Namespace[0].USR;
|
||||||
Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
|
ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
|
||||||
return {std::unique_ptr<Info>{std::move(I)},
|
return {std::unique_ptr<Info>{std::move(I)},
|
||||||
std::unique_ptr<Info>{std::move(Parent)}};
|
std::unique_ptr<Info>{std::move(ParentI)}};
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
llvm_unreachable("Invalid reference type");
|
llvm_unreachable("Invalid reference type for parent namespace");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,14 +464,16 @@ emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
|
||||||
Func.Access = clang::AccessSpecifier::AS_none;
|
Func.Access = clang::AccessSpecifier::AS_none;
|
||||||
|
|
||||||
// Wrap in enclosing scope
|
// Wrap in enclosing scope
|
||||||
auto I = llvm::make_unique<NamespaceInfo>();
|
auto ParentI = llvm::make_unique<NamespaceInfo>();
|
||||||
if (!Func.Namespace.empty())
|
if (!Func.Namespace.empty())
|
||||||
I->USR = Func.Namespace[0].USR;
|
ParentI->USR = Func.Namespace[0].USR;
|
||||||
else
|
else
|
||||||
I->USR = SymbolID();
|
ParentI->USR = SymbolID();
|
||||||
I->ChildFunctions.emplace_back(std::move(Func));
|
if (Func.Namespace.empty())
|
||||||
// Info es wrapped in its parent scope so it's returned in the second position
|
ParentI->Path = getInfoRelativePath(ParentI->Namespace);
|
||||||
return {nullptr, std::unique_ptr<Info>{std::move(I)}};
|
ParentI->ChildFunctions.emplace_back(std::move(Func));
|
||||||
|
// Info is wrapped in its parent scope so it's returned in the second position
|
||||||
|
return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||||
|
@ -455,11 +501,13 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
|
||||||
Func.Access = D->getAccess();
|
Func.Access = D->getAccess();
|
||||||
|
|
||||||
// Wrap in enclosing scope
|
// Wrap in enclosing scope
|
||||||
auto I = llvm::make_unique<RecordInfo>();
|
auto ParentI = llvm::make_unique<RecordInfo>();
|
||||||
I->USR = ParentUSR;
|
ParentI->USR = ParentUSR;
|
||||||
I->ChildFunctions.emplace_back(std::move(Func));
|
if (Func.Namespace.empty())
|
||||||
|
ParentI->Path = getInfoRelativePath(ParentI->Namespace);
|
||||||
|
ParentI->ChildFunctions.emplace_back(std::move(Func));
|
||||||
// Info is wrapped in its parent scope so it's returned in the second position
|
// Info is wrapped in its parent scope so it's returned in the second position
|
||||||
return {nullptr, std::unique_ptr<Info>{std::move(I)}};
|
return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||||
|
@ -475,36 +523,38 @@ emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
|
||||||
Enum.Scoped = D->isScoped();
|
Enum.Scoped = D->isScoped();
|
||||||
parseEnumerators(Enum, D);
|
parseEnumerators(Enum, D);
|
||||||
|
|
||||||
// Wrap in enclosing scope
|
// Put in global namespace
|
||||||
if (!Enum.Namespace.empty()) {
|
if (Enum.Namespace.empty()) {
|
||||||
switch (Enum.Namespace[0].RefType) {
|
auto ParentI = llvm::make_unique<NamespaceInfo>();
|
||||||
case InfoType::IT_namespace: {
|
ParentI->USR = SymbolID();
|
||||||
auto I = llvm::make_unique<NamespaceInfo>();
|
ParentI->ChildEnums.emplace_back(std::move(Enum));
|
||||||
I->USR = Enum.Namespace[0].USR;
|
ParentI->Path = getInfoRelativePath(ParentI->Namespace);
|
||||||
I->ChildEnums.emplace_back(std::move(Enum));
|
// Info is wrapped in its parent scope so it's returned in the second
|
||||||
// Info is wrapped in its parent scope so it's returned in the second
|
// position
|
||||||
// position
|
return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
|
||||||
return {nullptr, std::unique_ptr<Info>{std::move(I)}};
|
|
||||||
}
|
|
||||||
case InfoType::IT_record: {
|
|
||||||
auto I = llvm::make_unique<RecordInfo>();
|
|
||||||
I->USR = Enum.Namespace[0].USR;
|
|
||||||
I->ChildEnums.emplace_back(std::move(Enum));
|
|
||||||
// Info is wrapped in its parent scope so it's returned in the second
|
|
||||||
// position
|
|
||||||
return {nullptr, std::unique_ptr<Info>{std::move(I)}};
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put in global namespace
|
// Wrap in enclosing scope
|
||||||
auto I = llvm::make_unique<NamespaceInfo>();
|
switch (Enum.Namespace[0].RefType) {
|
||||||
I->USR = SymbolID();
|
case InfoType::IT_namespace: {
|
||||||
I->ChildEnums.emplace_back(std::move(Enum));
|
auto ParentI = llvm::make_unique<NamespaceInfo>();
|
||||||
// Info is wrapped in its parent scope so it's returned in the second position
|
ParentI->USR = Enum.Namespace[0].USR;
|
||||||
return {nullptr, std::unique_ptr<Info>{std::move(I)}};
|
ParentI->ChildEnums.emplace_back(std::move(Enum));
|
||||||
|
// Info is wrapped in its parent scope so it's returned in the second
|
||||||
|
// position
|
||||||
|
return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
|
||||||
|
}
|
||||||
|
case InfoType::IT_record: {
|
||||||
|
auto ParentI = llvm::make_unique<RecordInfo>();
|
||||||
|
ParentI->USR = Enum.Namespace[0].USR;
|
||||||
|
ParentI->ChildEnums.emplace_back(std::move(Enum));
|
||||||
|
// Info is wrapped in its parent scope so it's returned in the second
|
||||||
|
// position
|
||||||
|
return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Invalid reference type for parent namespace");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace serialize
|
} // namespace serialize
|
||||||
|
|
|
@ -113,6 +113,7 @@ static void FieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) {
|
||||||
static void InfoMapping(IO &IO, Info &I) {
|
static void InfoMapping(IO &IO, Info &I) {
|
||||||
IO.mapRequired("USR", I.USR);
|
IO.mapRequired("USR", I.USR);
|
||||||
IO.mapOptional("Name", I.Name, SmallString<16>());
|
IO.mapOptional("Name", I.Name, SmallString<16>());
|
||||||
|
IO.mapOptional("Path", I.Path, SmallString<128>());
|
||||||
IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());
|
IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());
|
||||||
IO.mapOptional("Description", I.Description);
|
IO.mapOptional("Description", I.Description);
|
||||||
}
|
}
|
||||||
|
@ -154,6 +155,7 @@ template <> struct MappingTraits<Reference> {
|
||||||
IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
|
IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
|
||||||
IO.mapOptional("Name", Ref.Name, SmallString<16>());
|
IO.mapOptional("Name", Ref.Name, SmallString<16>());
|
||||||
IO.mapOptional("USR", Ref.USR, SymbolID());
|
IO.mapOptional("USR", Ref.USR, SymbolID());
|
||||||
|
IO.mapOptional("Path", Ref.Path, SmallString<128>());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -110,12 +110,13 @@ bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A function to extract the appropriate path name for a given info's
|
// A function to extract the appropriate file name for a given info's
|
||||||
// documentation. The path returned is a composite of the parent namespaces as
|
// documentation. The path returned is a composite of the output directory, the
|
||||||
// directories plus the decl name as the filename.
|
// info's relative path and name and the extension. The relative path should
|
||||||
|
// have been constructed in the serialization phase.
|
||||||
//
|
//
|
||||||
// Example: Given the below, the <ext> path for class C will be <
|
// Example: Given the below, the <ext> path for class C will be
|
||||||
// root>/A/B/C.<ext>
|
// <root>/A/B/C.<ext>
|
||||||
//
|
//
|
||||||
// namespace A {
|
// namespace A {
|
||||||
// namesapce B {
|
// namesapce B {
|
||||||
|
@ -124,16 +125,14 @@ bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) {
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
llvm::Expected<llvm::SmallString<128>>
|
llvm::Expected<llvm::SmallString<128>> getInfoOutputFile(StringRef Root,
|
||||||
getInfoOutputFile(StringRef Root,
|
StringRef RelativePath,
|
||||||
llvm::SmallVectorImpl<doc::Reference> &Namespaces,
|
StringRef Name,
|
||||||
StringRef Name, StringRef Ext) {
|
StringRef Ext) {
|
||||||
std::error_code OK;
|
std::error_code OK;
|
||||||
llvm::SmallString<128> Path;
|
llvm::SmallString<128> Path;
|
||||||
llvm::sys::path::native(Root, Path);
|
llvm::sys::path::native(Root, Path);
|
||||||
for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
|
llvm::sys::path::append(Path, RelativePath);
|
||||||
llvm::sys::path::append(Path, R->Name);
|
|
||||||
|
|
||||||
if (CreateDirectory(Path))
|
if (CreateDirectory(Path))
|
||||||
return llvm::make_error<llvm::StringError>("Unable to create directory.\n",
|
return llvm::make_error<llvm::StringError>("Unable to create directory.\n",
|
||||||
llvm::inconvertibleErrorCode());
|
llvm::inconvertibleErrorCode());
|
||||||
|
@ -223,12 +222,11 @@ int main(int argc, const char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
doc::Info *I = Reduced.get().get();
|
doc::Info *I = Reduced.get().get();
|
||||||
|
auto InfoPath = getInfoOutputFile(OutDirectory, I->Path, I->extractName(),
|
||||||
auto InfoPath = getInfoOutputFile(OutDirectory, I->Namespace,
|
"." + Format);
|
||||||
I->extractName(), "." + Format);
|
|
||||||
if (!InfoPath) {
|
if (!InfoPath) {
|
||||||
llvm::errs() << toString(InfoPath.takeError()) << "\n";
|
llvm::errs() << toString(InfoPath.takeError()) << "\n";
|
||||||
continue;
|
return 1;
|
||||||
}
|
}
|
||||||
std::error_code FileErr;
|
std::error_code FileErr;
|
||||||
llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);
|
llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);
|
||||||
|
|
|
@ -57,7 +57,7 @@ TEST(HTMLGeneratorTest, emitNamespaceHTML) {
|
||||||
<div>
|
<div>
|
||||||
<h3>OneFunction</h3>
|
<h3>OneFunction</h3>
|
||||||
<p>
|
<p>
|
||||||
OneFunction()
|
OneFunction()
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<h2>Enums</h2>
|
<h2>Enums</h2>
|
||||||
|
@ -73,14 +73,16 @@ TEST(HTMLGeneratorTest, emitNamespaceHTML) {
|
||||||
TEST(HTMLGeneratorTest, emitRecordHTML) {
|
TEST(HTMLGeneratorTest, emitRecordHTML) {
|
||||||
RecordInfo I;
|
RecordInfo I;
|
||||||
I.Name = "r";
|
I.Name = "r";
|
||||||
|
I.Path = "X/Y/Z";
|
||||||
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
||||||
|
|
||||||
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
||||||
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
||||||
|
|
||||||
I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);
|
I.Members.emplace_back("int", "X/Y", "X", AccessSpecifier::AS_private);
|
||||||
I.TagType = TagTypeKind::TTK_Class;
|
I.TagType = TagTypeKind::TTK_Class;
|
||||||
I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
|
I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record,
|
||||||
|
llvm::SmallString<128>("path/to"));
|
||||||
I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
|
I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
|
||||||
|
|
||||||
I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
|
I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
|
||||||
|
@ -104,11 +106,13 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
|
||||||
Defined at line 10 of test.cpp
|
Defined at line 10 of test.cpp
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Inherits from F, G
|
Inherits from
|
||||||
|
<a href="../../../path/to/F.html">F</a>
|
||||||
|
, G
|
||||||
</p>
|
</p>
|
||||||
<h2>Members</h2>
|
<h2>Members</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>private int X</li>
|
<li>private <a href="../int.html">int</a> X</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Records</h2>
|
<h2>Records</h2>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -118,7 +122,7 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
|
||||||
<div>
|
<div>
|
||||||
<h3>OneFunction</h3>
|
<h3>OneFunction</h3>
|
||||||
<p>
|
<p>
|
||||||
OneFunction()
|
OneFunction()
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<h2>Enums</h2>
|
<h2>Enums</h2>
|
||||||
|
@ -139,8 +143,8 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) {
|
||||||
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
||||||
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
||||||
|
|
||||||
I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
|
I.ReturnType = TypeInfo(EmptySID, "float", InfoType::IT_default, "path/to");
|
||||||
I.Params.emplace_back("int", "P");
|
I.Params.emplace_back("int", "path/to", "P");
|
||||||
I.IsMethod = true;
|
I.IsMethod = true;
|
||||||
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
|
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
|
||||||
|
|
||||||
|
@ -156,7 +160,10 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) {
|
||||||
<div>
|
<div>
|
||||||
<h3>f</h3>
|
<h3>f</h3>
|
||||||
<p>
|
<p>
|
||||||
void f(int P)
|
<a href="path/to/float.html">float</a>
|
||||||
|
f(
|
||||||
|
<a href="path/to/int.html">int</a>
|
||||||
|
P)
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Defined at line 10 of test.cpp
|
Defined at line 10 of test.cpp
|
||||||
|
@ -261,8 +268,7 @@ TEST(HTMLGeneratorTest, emitCommentHTML) {
|
||||||
Brief description.
|
Brief description.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Extended description that
|
Extended description that continues onto the next line.
|
||||||
continues onto the next line.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -25,6 +25,7 @@ std::unique_ptr<Generator> getYAMLGenerator() {
|
||||||
TEST(YAMLGeneratorTest, emitNamespaceYAML) {
|
TEST(YAMLGeneratorTest, emitNamespaceYAML) {
|
||||||
NamespaceInfo I;
|
NamespaceInfo I;
|
||||||
I.Name = "Namespace";
|
I.Name = "Namespace";
|
||||||
|
I.Path = "path/to/A";
|
||||||
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
||||||
|
|
||||||
I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
|
I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
|
||||||
|
@ -45,6 +46,7 @@ TEST(YAMLGeneratorTest, emitNamespaceYAML) {
|
||||||
R"raw(---
|
R"raw(---
|
||||||
USR: '0000000000000000000000000000000000000000'
|
USR: '0000000000000000000000000000000000000000'
|
||||||
Name: 'Namespace'
|
Name: 'Namespace'
|
||||||
|
Path: 'path/to/A'
|
||||||
Namespace:
|
Namespace:
|
||||||
- Type: Namespace
|
- Type: Namespace
|
||||||
Name: 'A'
|
Name: 'A'
|
||||||
|
@ -69,15 +71,18 @@ ChildEnums:
|
||||||
TEST(YAMLGeneratorTest, emitRecordYAML) {
|
TEST(YAMLGeneratorTest, emitRecordYAML) {
|
||||||
RecordInfo I;
|
RecordInfo I;
|
||||||
I.Name = "r";
|
I.Name = "r";
|
||||||
|
I.Path = "path/to/r";
|
||||||
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
||||||
|
|
||||||
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
||||||
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
||||||
|
|
||||||
I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);
|
I.Members.emplace_back("int", "path/to/int", "X",
|
||||||
|
AccessSpecifier::AS_private);
|
||||||
I.TagType = TagTypeKind::TTK_Class;
|
I.TagType = TagTypeKind::TTK_Class;
|
||||||
I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
|
I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "path/to/F");
|
||||||
I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
|
I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
|
||||||
|
"path/to/G");
|
||||||
|
|
||||||
I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
|
I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
|
||||||
I.ChildFunctions.emplace_back();
|
I.ChildFunctions.emplace_back();
|
||||||
|
@ -95,6 +100,7 @@ TEST(YAMLGeneratorTest, emitRecordYAML) {
|
||||||
R"raw(---
|
R"raw(---
|
||||||
USR: '0000000000000000000000000000000000000000'
|
USR: '0000000000000000000000000000000000000000'
|
||||||
Name: 'r'
|
Name: 'r'
|
||||||
|
Path: 'path/to/r'
|
||||||
Namespace:
|
Namespace:
|
||||||
- Type: Namespace
|
- Type: Namespace
|
||||||
Name: 'A'
|
Name: 'A'
|
||||||
|
@ -108,14 +114,17 @@ TagType: Class
|
||||||
Members:
|
Members:
|
||||||
- Type:
|
- Type:
|
||||||
Name: 'int'
|
Name: 'int'
|
||||||
|
Path: 'path/to/int'
|
||||||
Name: 'X'
|
Name: 'X'
|
||||||
Access: Private
|
Access: Private
|
||||||
Parents:
|
Parents:
|
||||||
- Type: Record
|
- Type: Record
|
||||||
Name: 'F'
|
Name: 'F'
|
||||||
|
Path: 'path/to/F'
|
||||||
VirtualParents:
|
VirtualParents:
|
||||||
- Type: Record
|
- Type: Record
|
||||||
Name: 'G'
|
Name: 'G'
|
||||||
|
Path: 'path/to/G'
|
||||||
ChildRecords:
|
ChildRecords:
|
||||||
- Type: Record
|
- Type: Record
|
||||||
Name: 'ChildStruct'
|
Name: 'ChildStruct'
|
||||||
|
@ -139,8 +148,9 @@ TEST(YAMLGeneratorTest, emitFunctionYAML) {
|
||||||
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
||||||
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
||||||
|
|
||||||
I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
|
I.ReturnType =
|
||||||
I.Params.emplace_back("int", "P");
|
TypeInfo(EmptySID, "void", InfoType::IT_default, "path/to/void");
|
||||||
|
I.Params.emplace_back("int", "path/to/int", "P");
|
||||||
I.IsMethod = true;
|
I.IsMethod = true;
|
||||||
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
|
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
|
||||||
|
|
||||||
|
@ -170,10 +180,12 @@ Parent:
|
||||||
Params:
|
Params:
|
||||||
- Type:
|
- Type:
|
||||||
Name: 'int'
|
Name: 'int'
|
||||||
|
Path: 'path/to/int'
|
||||||
Name: 'P'
|
Name: 'P'
|
||||||
ReturnType:
|
ReturnType:
|
||||||
Type:
|
Type:
|
||||||
Name: 'void'
|
Name: 'void'
|
||||||
|
Path: 'path/to/void'
|
||||||
...
|
...
|
||||||
)raw";
|
)raw";
|
||||||
EXPECT_EQ(Expected, Actual.str());
|
EXPECT_EQ(Expected, Actual.str());
|
||||||
|
|
Loading…
Reference in New Issue