Index: clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp
+++ clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp
@@ -148,6 +148,8 @@
return decodeRecord(R, I->USR, Blob);
case NAMESPACE_NAME:
return decodeRecord(R, I->Name, Blob);
+ case NAMESPACE_PATH:
+ return decodeRecord(R, I->Path, Blob);
default:
return llvm::make_error(
"Invalid field for NamespaceInfo.\n", llvm::inconvertibleErrorCode());
@@ -161,6 +163,8 @@
return decodeRecord(R, I->USR, Blob);
case RECORD_NAME:
return decodeRecord(R, I->Name, Blob);
+ case RECORD_PATH:
+ return decodeRecord(R, I->Path, Blob);
case RECORD_DEFLOCATION:
return decodeRecord(R, I->DefLoc, Blob);
case RECORD_LOCATION:
@@ -286,6 +290,8 @@
return decodeRecord(R, I->Name, Blob);
case REFERENCE_TYPE:
return decodeRecord(R, I->RefType, Blob);
+ case REFERENCE_PATH:
+ return decodeRecord(R, I->Path, Blob);
case REFERENCE_FIELD:
return decodeRecord(R, F, Blob);
default:
@@ -685,7 +691,7 @@
std::unique_ptr I = llvm::make_unique();
if (auto Err = readBlock(ID, static_cast(I.get())))
return std::move(Err);
- return std::unique_ptr{std::move(I)};;
+ return std::unique_ptr{std::move(I)};
}
llvm::Expected>
Index: clang-tools-extra/trunk/clang-doc/BitcodeWriter.h
===================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeWriter.h
+++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.h
@@ -91,6 +91,7 @@
MEMBER_TYPE_ACCESS,
NAMESPACE_USR,
NAMESPACE_NAME,
+ NAMESPACE_PATH,
ENUM_USR,
ENUM_NAME,
ENUM_DEFLOCATION,
@@ -99,6 +100,7 @@
ENUM_SCOPED,
RECORD_USR,
RECORD_NAME,
+ RECORD_PATH,
RECORD_DEFLOCATION,
RECORD_LOCATION,
RECORD_TAG_TYPE,
@@ -106,6 +108,7 @@
REFERENCE_USR,
REFERENCE_NAME,
REFERENCE_TYPE,
+ REFERENCE_PATH,
REFERENCE_FIELD,
RI_LAST,
RI_FIRST = VERSION
Index: clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
+++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
@@ -148,6 +148,7 @@
{MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
{NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
{NAMESPACE_NAME, {"Name", &StringAbbrev}},
+ {NAMESPACE_PATH, {"Path", &StringAbbrev}},
{ENUM_USR, {"USR", &SymbolIDAbbrev}},
{ENUM_NAME, {"Name", &StringAbbrev}},
{ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
@@ -156,6 +157,7 @@
{ENUM_SCOPED, {"Scoped", &BoolAbbrev}},
{RECORD_USR, {"USR", &SymbolIDAbbrev}},
{RECORD_NAME, {"Name", &StringAbbrev}},
+ {RECORD_PATH, {"Path", &StringAbbrev}},
{RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
{RECORD_LOCATION, {"Location", &LocationAbbrev}},
{RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
@@ -169,6 +171,7 @@
{REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
{REFERENCE_NAME, {"Name", &StringAbbrev}},
{REFERENCE_TYPE, {"RefType", &IntAbbrev}},
+ {REFERENCE_PATH, {"Path", &StringAbbrev}},
{REFERENCE_FIELD, {"Field", &IntAbbrev}}};
assert(Inits.size() == RecordIdCount);
for (const auto &Init : Inits) {
@@ -199,18 +202,20 @@
{ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_MEMBER,
ENUM_SCOPED}},
// Namespace Block
- {BI_NAMESPACE_BLOCK_ID, {NAMESPACE_USR, NAMESPACE_NAME}},
+ {BI_NAMESPACE_BLOCK_ID,
+ {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},
// Record Block
{BI_RECORD_BLOCK_ID,
- {RECORD_USR, RECORD_NAME, RECORD_DEFLOCATION, RECORD_LOCATION,
- RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},
+ {RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,
+ RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},
// Function Block
{BI_FUNCTION_BLOCK_ID,
{FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
// Reference Block
{BI_REFERENCE_BLOCK_ID,
- {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_FIELD}}};
+ {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_PATH,
+ REFERENCE_FIELD}}};
// AbbreviationMap
@@ -381,6 +386,7 @@
emitRecord(R.USR, REFERENCE_USR);
emitRecord(R.Name, REFERENCE_NAME);
emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
+ emitRecord(R.Path, REFERENCE_PATH);
emitRecord((unsigned)Field, REFERENCE_FIELD);
}
@@ -428,6 +434,7 @@
StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
emitRecord(I.USR, NAMESPACE_USR);
emitRecord(I.Name, NAMESPACE_NAME);
+ emitRecord(I.Path, NAMESPACE_PATH);
for (const auto &N : I.Namespace)
emitBlock(N, FieldId::F_namespace);
for (const auto &CI : I.Description)
@@ -463,6 +470,7 @@
StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
emitRecord(I.USR, RECORD_USR);
emitRecord(I.Name, RECORD_NAME);
+ emitRecord(I.Path, RECORD_PATH);
for (const auto &N : I.Namespace)
emitBlock(N, FieldId::F_namespace);
for (const auto &CI : I.Description)
Index: clang-tools-extra/trunk/clang-doc/Generators.h
===================================================================
--- clang-tools-extra/trunk/clang-doc/Generators.h
+++ clang-tools-extra/trunk/clang-doc/Generators.h
@@ -38,8 +38,6 @@
std::string getTagType(TagTypeKind AS);
-std::string genReferenceList(const llvm::SmallVectorImpl &Refs);
-
} // namespace doc
} // namespace clang
Index: clang-tools-extra/trunk/clang-doc/Generators.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/Generators.cpp
+++ clang-tools-extra/trunk/clang-doc/Generators.cpp
@@ -57,19 +57,6 @@
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 &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
// and thus register the generators.
extern volatile int YAMLGeneratorAnchorSource;
Index: clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
+++ clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
@@ -18,13 +18,6 @@
namespace clang {
namespace doc {
-template ::value>>
-static void AppendVector(std::vector &&New,
- std::vector &Original) {
- std::move(New.begin(), New.end(), std::back_inserter(Original));
-}
-
namespace {
class HTMLTag {
@@ -40,6 +33,7 @@
TAG_P,
TAG_UL,
TAG_LI,
+ TAG_A,
};
HTMLTag() = default;
@@ -58,15 +52,22 @@
TagType Value;
};
+enum NodeType {
+ NODE_TEXT,
+ NODE_TAG,
+};
+
struct HTMLNode {
+ HTMLNode(NodeType Type) : Type(Type) {}
virtual ~HTMLNode() = default;
virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0;
+ NodeType Type; // Type of node
};
struct TextNode : public HTMLNode {
- TextNode(llvm::StringRef Text, bool Indented)
- : Text(Text), Indented(Indented) {}
+ TextNode(const Twine &Text, bool Indented = true)
+ : HTMLNode(NodeType::NODE_TEXT), Text(Text.str()), Indented(Indented) {}
std::string Text; // Content of node
bool Indented; // Indicates if an indentation must be rendered before the text
@@ -75,7 +76,8 @@
struct TagNode : public HTMLNode {
TagNode(HTMLTag Tag)
- : Tag(Tag), InlineChildren(Tag.HasInlineChildren()),
+ : HTMLNode(NodeType::NODE_TAG), Tag(Tag),
+ InlineChildren(Tag.HasInlineChildren()),
SelfClosing(Tag.IsSelfClosing()) {}
TagNode(HTMLTag Tag, const Twine &Text) : TagNode(Tag) {
Children.emplace_back(
@@ -121,6 +123,7 @@
case HTMLTag::TAG_P:
case HTMLTag::TAG_UL:
case HTMLTag::TAG_LI:
+ case HTMLTag::TAG_A:
return false;
}
llvm_unreachable("Unhandled HTMLTag::TagType");
@@ -134,6 +137,7 @@
case HTMLTag::TAG_H2:
case HTMLTag::TAG_H3:
case HTMLTag::TAG_LI:
+ case HTMLTag::TAG_A:
return true;
case HTMLTag::TAG_DIV:
case HTMLTag::TAG_P:
@@ -163,6 +167,8 @@
return llvm::SmallString<16>("ul");
case HTMLTag::TAG_LI:
return llvm::SmallString<16>("li");
+ case HTMLTag::TAG_A:
+ return llvm::SmallString<16>("a");
}
llvm_unreachable("Unhandled HTMLTag::TagType");
}
@@ -185,21 +191,87 @@
OS << ">";
if (!InlineChildren)
OS << "\n";
- int ChildrenIndentation = InlineChildren ? 0 : IndentationLevel + 1;
+ bool NewLineRendered = true;
for (const auto &C : Children) {
+ int ChildrenIndentation =
+ InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;
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";
+ NewLineRendered = true;
+ } else
+ NewLineRendered = false;
}
if (!InlineChildren)
OS.indent(IndentationLevel * 2);
OS << "" << Tag.ToString() << ">";
}
+template ::value>>
+static void AppendVector(std::vector &&New,
+ std::vector &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
+static std::unique_ptr genLink(const Twine &Text, const Twine &Link) {
+ auto LinkNode = llvm::make_unique(HTMLTag::TAG_A, Text);
+ LinkNode->Attributes.try_emplace("href", Link.str());
+ return LinkNode;
+}
+
+static std::unique_ptr genTypeReference(const Reference &Type,
+ StringRef CurrentDirectory) {
+ if (Type.Path.empty())
+ return llvm::make_unique(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>
+genReferenceList(const llvm::SmallVectorImpl &Refs,
+ const StringRef &CurrentDirectory) {
+ std::vector> Out;
+ for (const auto &R : Refs) {
+ if (&R != Refs.begin())
+ Out.emplace_back(llvm::make_unique(", "));
+ Out.emplace_back(genTypeReference(R, CurrentDirectory));
+ }
+ return Out;
+}
+
static std::vector> genHTML(const EnumInfo &I);
-static std::vector> genHTML(const FunctionInfo &I);
+static std::vector> genHTML(const FunctionInfo &I,
+ StringRef ParentInfoDir);
static std::vector>
genEnumsBlock(const std::vector &Enums) {
@@ -229,7 +301,8 @@
}
static std::vector>
-genFunctionsBlock(const std::vector &Functions) {
+genFunctionsBlock(const std::vector &Functions,
+ StringRef ParentInfoDir) {
if (Functions.empty())
return {};
@@ -238,14 +311,15 @@
Out.emplace_back(llvm::make_unique(HTMLTag::TAG_DIV));
auto &DivBody = Out.back();
for (const auto &F : Functions) {
- std::vector> Nodes = genHTML(F);
+ std::vector> Nodes = genHTML(F, ParentInfoDir);
AppendVector(std::move(Nodes), DivBody->Children);
}
return Out;
}
static std::vector>
-genRecordMembersBlock(const llvm::SmallVector &Members) {
+genRecordMembersBlock(const llvm::SmallVector &Members,
+ StringRef ParentInfoDir) {
if (Members.empty())
return {};
@@ -257,8 +331,11 @@
std::string Access = getAccess(M.Access);
if (Access != "")
Access = Access + " ";
- ULBody->Children.emplace_back(llvm::make_unique(
- HTMLTag::TAG_LI, Access + M.Type.Name + " " + M.Name));
+ auto LIBody = llvm::make_unique(HTMLTag::TAG_LI);
+ LIBody->Children.emplace_back(llvm::make_unique(Access));
+ LIBody->Children.emplace_back(genTypeReference(M.Type, ParentInfoDir));
+ LIBody->Children.emplace_back(llvm::make_unique(" " + M.Name));
+ ULBody->Children.emplace_back(std::move(LIBody));
}
return Out;
}
@@ -346,25 +423,35 @@
return Out;
}
-static std::vector> genHTML(const FunctionInfo &I) {
+static std::vector> genHTML(const FunctionInfo &I,
+ StringRef ParentInfoDir) {
std::vector> Out;
Out.emplace_back(llvm::make_unique(HTMLTag::TAG_H3, I.Name));
- std::string Buffer;
- llvm::raw_string_ostream Stream(Buffer);
- for (const auto &P : I.Params) {
- if (&P != I.Params.begin())
- Stream << ", ";
- Stream << P.Type.Name + " " + P.Name;
- }
+ Out.emplace_back(llvm::make_unique(HTMLTag::TAG_P));
+ auto &FunctionHeader = Out.back();
std::string Access = getAccess(I.Access);
if (Access != "")
- Access = Access + " ";
+ FunctionHeader->Children.emplace_back(
+ llvm::make_unique(Access + " "));
+ if (I.ReturnType.Type.Name != "") {
+ FunctionHeader->Children.emplace_back(
+ genTypeReference(I.ReturnType.Type, ParentInfoDir));
+ FunctionHeader->Children.emplace_back(llvm::make_unique(" "));
+ }
+ FunctionHeader->Children.emplace_back(
+ llvm::make_unique(I.Name + "("));
- Out.emplace_back(llvm::make_unique(
- HTMLTag::TAG_P, Access + I.ReturnType.Type.Name + " " + I.Name + "(" +
- Stream.str() + ")"));
+ for (const auto &P : I.Params) {
+ if (&P != I.Params.begin())
+ FunctionHeader->Children.emplace_back(llvm::make_unique(", "));
+ FunctionHeader->Children.emplace_back(
+ genTypeReference(P.Type, ParentInfoDir));
+ FunctionHeader->Children.emplace_back(
+ llvm::make_unique(" " + P.Name));
+ }
+ FunctionHeader->Children.emplace_back(llvm::make_unique(")"));
if (I.DefLoc)
Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
@@ -398,7 +485,7 @@
AppendVector(std::move(ChildRecords), Out);
std::vector> ChildFunctions =
- genFunctionsBlock(I.ChildFunctions);
+ genFunctionsBlock(I.ChildFunctions, I.Path);
AppendVector(std::move(ChildFunctions), Out);
std::vector> ChildEnums =
genEnumsBlock(I.ChildEnums);
@@ -420,29 +507,34 @@
if (!I.Description.empty())
Out.emplace_back(genHTML(I.Description));
- std::string Parents = genReferenceList(I.Parents);
- std::string VParents = genReferenceList(I.VirtualParents);
+ std::vector> Parents =
+ genReferenceList(I.Parents, I.Path);
+ std::vector> VParents =
+ genReferenceList(I.VirtualParents, I.Path);
if (!Parents.empty() || !VParents.empty()) {
+ Out.emplace_back(llvm::make_unique(HTMLTag::TAG_P));
+ auto &PBody = Out.back();
+ PBody->Children.emplace_back(llvm::make_unique("Inherits from "));
if (Parents.empty())
- Out.emplace_back(llvm::make_unique(HTMLTag::TAG_P,
- "Inherits from " + VParents));
+ AppendVector(std::move(VParents), PBody->Children);
else if (VParents.empty())
- Out.emplace_back(llvm::make_unique(HTMLTag::TAG_P,
- "Inherits from " + Parents));
- else
- Out.emplace_back(llvm::make_unique(
- HTMLTag::TAG_P, "Inherits from " + Parents + ", " + VParents));
+ AppendVector(std::move(Parents), PBody->Children);
+ else {
+ AppendVector(std::move(Parents), PBody->Children);
+ PBody->Children.emplace_back(llvm::make_unique(", "));
+ AppendVector(std::move(VParents), PBody->Children);
+ }
}
std::vector> Members =
- genRecordMembersBlock(I.Members);
+ genRecordMembersBlock(I.Members, I.Path);
AppendVector(std::move(Members), Out);
std::vector> ChildRecords =
genReferencesBlock(I.ChildRecords, "Records");
AppendVector(std::move(ChildRecords), Out);
std::vector> ChildFunctions =
- genFunctionsBlock(I.ChildFunctions);
+ genFunctionsBlock(I.ChildFunctions, I.Path);
AppendVector(std::move(ChildFunctions), Out);
std::vector> ChildEnums =
genEnumsBlock(I.ChildEnums);
@@ -492,7 +584,7 @@
}
case InfoType::IT_function: {
std::vector> Nodes =
- genHTML(*static_cast(I));
+ genHTML(*static_cast(I), "");
AppendVector(std::move(Nodes), MainContentNode->Children);
break;
}
Index: clang-tools-extra/trunk/clang-doc/MDGenerator.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/MDGenerator.cpp
+++ clang-tools-extra/trunk/clang-doc/MDGenerator.cpp
@@ -28,6 +28,18 @@
return "**" + Text.str() + "**";
}
+static std::string
+genReferenceList(const llvm::SmallVectorImpl &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) {
OS << Text << "\n\n";
}
Index: clang-tools-extra/trunk/clang-doc/Representation.h
===================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.h
+++ clang-tools-extra/trunk/clang-doc/Representation.h
@@ -114,8 +114,11 @@
struct Reference {
Reference() = default;
Reference(llvm::StringRef Name) : Name(Name) {}
+ Reference(llvm::StringRef Name, StringRef Path) : Name(Name), Path(Path) {}
Reference(SymbolID USR, StringRef Name, InfoType 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 {
return std::tie(USR, Name, RefType) ==
@@ -127,6 +130,8 @@
InfoType RefType = InfoType::IT_default; // Indicates the type of this
// Reference (namespace, record,
// function, enum, default).
+ llvm::SmallString<128> Path; // Path of directory where the clang-doc
+ // generated file will be saved
};
// A base struct for TypeInfos
@@ -134,7 +139,10 @@
TypeInfo() = default;
TypeInfo(SymbolID Type, StringRef Field, InfoType 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, StringRef Path) : Type(RefName, Path) {}
bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
@@ -144,11 +152,13 @@
// Info for field types.
struct FieldTypeInfo : public TypeInfo {
FieldTypeInfo() = default;
- FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT,
+ FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,
llvm::StringRef Name)
- : TypeInfo(Type, Field, IT), Name(Name) {}
+ : TypeInfo(Type, Field, IT, Path), Name(Name) {}
FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef 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 {
return std::tie(Type, Name) == std::tie(Other.Type, Other.Name);
@@ -160,12 +170,15 @@
// Info for member types.
struct MemberTypeInfo : public FieldTypeInfo {
MemberTypeInfo() = default;
- MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT,
+ MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,
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,
AccessSpecifier 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 {
return std::tie(Type, Name, Access) ==
@@ -220,6 +233,8 @@
llvm::SmallVector
Namespace; // List of parent namespaces for this decl.
std::vector 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);
bool mergeable(const Info &Other);
Index: clang-tools-extra/trunk/clang-doc/Representation.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.cpp
+++ clang-tools-extra/trunk/clang-doc/Representation.cpp
@@ -118,6 +118,8 @@
USR = Other.USR;
if (Name == "")
Name = Other.Name;
+ if (Path == "")
+ Path = Other.Path;
if (Namespace.empty())
Namespace = std::move(Other.Namespace);
// Unconditionally extend the description, since each decl may have a comment.
Index: clang-tools-extra/trunk/clang-doc/Serialize.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/Serialize.cpp
+++ clang-tools-extra/trunk/clang-doc/Serialize.cpp
@@ -24,6 +24,43 @@
return llvm::SHA1::hash(arrayRefFromStringRef(USR));
}
+template
+static void
+populateParentNamespaces(llvm::SmallVector &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
+// /A/B
+//
+// namespace A {
+// namesapce B {
+//
+// class C {};
+//
+// }
+// }
+llvm::SmallString<128>
+getInfoRelativePath(const llvm::SmallVectorImpl &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 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
: public ConstCommentVisitor {
public:
@@ -203,13 +240,13 @@
// valid, as opposed to an assert.
if (const auto *N = dyn_cast(T)) {
I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
- InfoType::IT_enum, F->getNameAsString(),
- N->getAccessUnsafe());
+ InfoType::IT_enum, getInfoRelativePath(N),
+ F->getNameAsString(), N->getAccessUnsafe());
continue;
} else if (const auto *N = dyn_cast(T)) {
I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
- InfoType::IT_record, F->getNameAsString(),
- N->getAccessUnsafe());
+ InfoType::IT_record, getInfoRelativePath(N),
+ F->getNameAsString(), N->getAccessUnsafe());
continue;
}
}
@@ -228,11 +265,13 @@
if (const auto *T = getDeclForType(P->getOriginalType())) {
if (const auto *N = dyn_cast(T)) {
I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
- InfoType::IT_enum, P->getNameAsString());
+ InfoType::IT_enum, getInfoRelativePath(N),
+ P->getNameAsString());
continue;
} else if (const auto *N = dyn_cast(T)) {
I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
- InfoType::IT_record, P->getNameAsString());
+ InfoType::IT_record, getInfoRelativePath(N),
+ P->getNameAsString());
continue;
}
}
@@ -254,14 +293,15 @@
InfoType::IT_record);
} else if (const RecordDecl *P = getDeclForType(B.getType()))
I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
- InfoType::IT_record);
+ InfoType::IT_record, getInfoRelativePath(P));
else
I.Parents.emplace_back(B.getType().getAsString());
}
for (const CXXBaseSpecifier &B : D->vbases()) {
if (const auto *P = getDeclForType(B.getType()))
I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
- InfoType::IT_record);
+ InfoType::IT_record,
+ getInfoRelativePath(P));
else
I.VirtualParents.emplace_back(B.getType().getAsString());
}
@@ -270,14 +310,14 @@
template
static void
populateParentNamespaces(llvm::SmallVector &Namespaces,
- const T *D, bool &IsAnonymousNamespace) {
+ const T *D, bool &IsInAnonymousNamespace) {
const auto *DC = dyn_cast(D);
while ((DC = DC->getParent())) {
if (const auto *N = dyn_cast(DC)) {
std::string Namespace;
if (N->isAnonymousNamespace()) {
Namespace = "@nonymous_namespace";
- IsAnonymousNamespace = true;
+ IsInAnonymousNamespace = true;
} else
Namespace = N->getNameAsString();
Namespaces.emplace_back(getUSRForDecl(N), Namespace,
@@ -324,11 +364,11 @@
populateSymbolInfo(I, D, FC, LineNumber, Filename, IsInAnonymousNamespace);
if (const auto *T = getDeclForType(D->getReturnType())) {
if (dyn_cast(T))
- I.ReturnType =
- TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum);
+ I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
+ InfoType::IT_enum, getInfoRelativePath(T));
else if (dyn_cast(T))
- I.ReturnType =
- TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record);
+ I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
+ InfoType::IT_record, getInfoRelativePath(T));
} else {
I.ReturnType = TypeInfo(D->getReturnType().getAsString());
}
@@ -347,16 +387,18 @@
I->Name = D->isAnonymousNamespace()
? llvm::SmallString<16>("@nonymous_namespace")
: I->Name;
+ I->Path = getInfoRelativePath(I->Namespace);
if (I->Namespace.empty() && I->USR == SymbolID())
return {std::unique_ptr{std::move(I)}, nullptr};
- SymbolID ParentUSR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;
-
- auto Parent = llvm::make_unique();
- Parent->USR = ParentUSR;
- Parent->ChildNamespaces.emplace_back(I->USR, I->Name, InfoType::IT_namespace);
+ auto ParentI = llvm::make_unique();
+ ParentI->USR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;
+ ParentI->ChildNamespaces.emplace_back(I->USR, I->Name,
+ InfoType::IT_namespace);
+ if (I->Namespace.empty())
+ ParentI->Path = getInfoRelativePath(ParentI->Namespace);
return {std::unique_ptr{std::move(I)},
- std::unique_ptr{std::move(Parent)}};
+ std::unique_ptr{std::move(ParentI)}};
}
std::pair, std::unique_ptr>
@@ -378,32 +420,34 @@
}
parseBases(*I, C);
}
+ I->Path = getInfoRelativePath(I->Namespace);
if (I->Namespace.empty()) {
- auto Parent = llvm::make_unique();
- Parent->USR = SymbolID();
- Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+ auto ParentI = llvm::make_unique();
+ ParentI->USR = SymbolID();
+ ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+ ParentI->Path = getInfoRelativePath(ParentI->Namespace);
return {std::unique_ptr{std::move(I)},
- std::unique_ptr{std::move(Parent)}};
+ std::unique_ptr{std::move(ParentI)}};
}
switch (I->Namespace[0].RefType) {
case InfoType::IT_namespace: {
- auto Parent = llvm::make_unique();
- Parent->USR = I->Namespace[0].USR;
- Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+ auto ParentI = llvm::make_unique();
+ ParentI->USR = I->Namespace[0].USR;
+ ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
return {std::unique_ptr{std::move(I)},
- std::unique_ptr{std::move(Parent)}};
+ std::unique_ptr{std::move(ParentI)}};
}
case InfoType::IT_record: {
- auto Parent = llvm::make_unique();
- Parent->USR = I->Namespace[0].USR;
- Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+ auto ParentI = llvm::make_unique();
+ ParentI->USR = I->Namespace[0].USR;
+ ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
return {std::unique_ptr{std::move(I)},
- std::unique_ptr{std::move(Parent)}};
+ std::unique_ptr{std::move(ParentI)}};
}
default:
- llvm_unreachable("Invalid reference type");
+ llvm_unreachable("Invalid reference type for parent namespace");
}
}
@@ -420,14 +464,16 @@
Func.Access = clang::AccessSpecifier::AS_none;
// Wrap in enclosing scope
- auto I = llvm::make_unique();
+ auto ParentI = llvm::make_unique();
if (!Func.Namespace.empty())
- I->USR = Func.Namespace[0].USR;
+ ParentI->USR = Func.Namespace[0].USR;
else
- I->USR = SymbolID();
- I->ChildFunctions.emplace_back(std::move(Func));
- // Info es wrapped in its parent scope so it's returned in the second position
- return {nullptr, std::unique_ptr{std::move(I)}};
+ ParentI->USR = SymbolID();
+ 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
+ return {nullptr, std::unique_ptr{std::move(ParentI)}};
}
std::pair, std::unique_ptr>
@@ -455,11 +501,13 @@
Func.Access = D->getAccess();
// Wrap in enclosing scope
- auto I = llvm::make_unique();
- I->USR = ParentUSR;
- I->ChildFunctions.emplace_back(std::move(Func));
+ auto ParentI = llvm::make_unique();
+ ParentI->USR = ParentUSR;
+ 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
- return {nullptr, std::unique_ptr{std::move(I)}};
+ return {nullptr, std::unique_ptr{std::move(ParentI)}};
}
std::pair, std::unique_ptr>
@@ -475,36 +523,38 @@
Enum.Scoped = D->isScoped();
parseEnumerators(Enum, D);
- // Wrap in enclosing scope
- if (!Enum.Namespace.empty()) {
- switch (Enum.Namespace[0].RefType) {
- case InfoType::IT_namespace: {
- auto I = llvm::make_unique();
- 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{std::move(I)}};
- }
- case InfoType::IT_record: {
- auto I = llvm::make_unique();
- 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{std::move(I)}};
- }
- default:
- break;
- }
+ // Put in global namespace
+ if (Enum.Namespace.empty()) {
+ auto ParentI = llvm::make_unique();
+ ParentI->USR = SymbolID();
+ ParentI->ChildEnums.emplace_back(std::move(Enum));
+ ParentI->Path = getInfoRelativePath(ParentI->Namespace);
+ // Info is wrapped in its parent scope so it's returned in the second
+ // position
+ return {nullptr, std::unique_ptr{std::move(ParentI)}};
}
- // Put in global namespace
- auto I = llvm::make_unique();
- I->USR = SymbolID();
- 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{std::move(I)}};
+ // Wrap in enclosing scope
+ switch (Enum.Namespace[0].RefType) {
+ case InfoType::IT_namespace: {
+ auto ParentI = llvm::make_unique();
+ 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{std::move(ParentI)}};
+ }
+ case InfoType::IT_record: {
+ auto ParentI = llvm::make_unique();
+ 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{std::move(ParentI)}};
+ }
+ default:
+ llvm_unreachable("Invalid reference type for parent namespace");
+ }
}
} // namespace serialize
Index: clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp
+++ clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp
@@ -113,6 +113,7 @@
static void InfoMapping(IO &IO, Info &I) {
IO.mapRequired("USR", I.USR);
IO.mapOptional("Name", I.Name, SmallString<16>());
+ IO.mapOptional("Path", I.Path, SmallString<128>());
IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector());
IO.mapOptional("Description", I.Description);
}
@@ -154,6 +155,7 @@
IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
IO.mapOptional("Name", Ref.Name, SmallString<16>());
IO.mapOptional("USR", Ref.USR, SymbolID());
+ IO.mapOptional("Path", Ref.Path, SmallString<128>());
}
};
Index: clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
+++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
@@ -110,12 +110,13 @@
return false;
}
-// A function to extract the appropriate path name for a given info's
-// documentation. The path returned is a composite of the parent namespaces as
-// directories plus the decl name as the filename.
+// A function to extract the appropriate file name for a given info's
+// documentation. The path returned is a composite of the output directory, the
+// 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 path for class C will be <
-// root>/A/B/C.
+// Example: Given the below, the path for class C will be
+// /A/B/C.
//
// namespace A {
// namesapce B {
@@ -124,16 +125,14 @@
//
// }
// }
-llvm::Expected>
-getInfoOutputFile(StringRef Root,
- llvm::SmallVectorImpl &Namespaces,
- StringRef Name, StringRef Ext) {
+llvm::Expected> getInfoOutputFile(StringRef Root,
+ StringRef RelativePath,
+ StringRef Name,
+ StringRef Ext) {
std::error_code OK;
llvm::SmallString<128> Path;
llvm::sys::path::native(Root, Path);
- for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
- llvm::sys::path::append(Path, R->Name);
-
+ llvm::sys::path::append(Path, RelativePath);
if (CreateDirectory(Path))
return llvm::make_error("Unable to create directory.\n",
llvm::inconvertibleErrorCode());
@@ -223,12 +222,11 @@
}
doc::Info *I = Reduced.get().get();
-
- auto InfoPath = getInfoOutputFile(OutDirectory, I->Namespace,
- I->extractName(), "." + Format);
+ auto InfoPath = getInfoOutputFile(OutDirectory, I->Path, I->extractName(),
+ "." + Format);
if (!InfoPath) {
llvm::errs() << toString(InfoPath.takeError()) << "\n";
- continue;
+ return 1;
}
std::error_code FileErr;
llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);
Index: clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp
===================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp
+++ clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp
@@ -57,7 +57,7 @@
OneFunction
- OneFunction()
+ OneFunction()
Enums
@@ -73,14 +73,16 @@
TEST(HTMLGeneratorTest, emitRecordHTML) {
RecordInfo I;
I.Name = "r";
+ I.Path = "X/Y/Z";
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
I.DefLoc = Location(10, 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.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.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
@@ -104,11 +106,13 @@
Defined at line 10 of test.cpp
- Inherits from F, G
+ Inherits from
+ F
+ , G
Members
- - private int X
+ - private int X
Records
@@ -118,7 +122,7 @@
OneFunction
- OneFunction()
+ OneFunction()
Enums
@@ -139,8 +143,8 @@
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
- I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
- I.Params.emplace_back("int", "P");
+ I.ReturnType = TypeInfo(EmptySID, "float", InfoType::IT_default, "path/to");
+ I.Params.emplace_back("int", "path/to", "P");
I.IsMethod = true;
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
@@ -156,7 +160,10 @@
f
- void f(int P)
+ float
+ f(
+ int
+ P)
Defined at line 10 of test.cpp
@@ -261,8 +268,7 @@
Brief description.
- Extended description that
- continues onto the next line.
+ Extended description that continues onto the next line.
Index: clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp
===================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -25,6 +25,7 @@
TEST(YAMLGeneratorTest, emitNamespaceYAML) {
NamespaceInfo I;
I.Name = "Namespace";
+ I.Path = "path/to/A";
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
@@ -45,6 +46,7 @@
R"raw(---
USR: '0000000000000000000000000000000000000000'
Name: 'Namespace'
+Path: 'path/to/A'
Namespace:
- Type: Namespace
Name: 'A'
@@ -69,15 +71,18 @@
TEST(YAMLGeneratorTest, emitRecordYAML) {
RecordInfo I;
I.Name = "r";
+ I.Path = "path/to/r";
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
I.DefLoc = Location(10, 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.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
- I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
+ I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "path/to/F");
+ I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
+ "path/to/G");
I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
I.ChildFunctions.emplace_back();
@@ -95,6 +100,7 @@
R"raw(---
USR: '0000000000000000000000000000000000000000'
Name: 'r'
+Path: 'path/to/r'
Namespace:
- Type: Namespace
Name: 'A'
@@ -108,14 +114,17 @@
Members:
- Type:
Name: 'int'
+ Path: 'path/to/int'
Name: 'X'
Access: Private
Parents:
- Type: Record
Name: 'F'
+ Path: 'path/to/F'
VirtualParents:
- Type: Record
Name: 'G'
+ Path: 'path/to/G'
ChildRecords:
- Type: Record
Name: 'ChildStruct'
@@ -139,8 +148,9 @@
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
- I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
- I.Params.emplace_back("int", "P");
+ I.ReturnType =
+ TypeInfo(EmptySID, "void", InfoType::IT_default, "path/to/void");
+ I.Params.emplace_back("int", "path/to/int", "P");
I.IsMethod = true;
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
@@ -170,10 +180,12 @@
Params:
- Type:
Name: 'int'
+ Path: 'path/to/int'
Name: 'P'
ReturnType:
Type:
Name: 'void'
+ Path: 'path/to/void'
...
)raw";
EXPECT_EQ(Expected, Actual.str());