[clang-tools-extra] r368070 - [clang-doc] Add index in each info html file

Diego Astiazaran via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 6 11:31:46 PDT 2019


Author: diegoastiazaran
Date: Tue Aug  6 11:31:46 2019
New Revision: 368070

URL: http://llvm.org/viewvc/llvm-project?rev=368070&view=rev
Log:
[clang-doc] Add index in each info html file

An index structure is created while generating the output file for each
info. This structure is parsed to JSON and written to a file in the
output directory. The html for the index is not rendered by clang-doc. A
Javascript file is included in the output directory, this will the JSON
file and insert HTML elements into the file.

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

Added:
    clang-tools-extra/trunk/clang-doc/assets/
    clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css
    clang-tools-extra/trunk/clang-doc/assets/index.js
    clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp
Removed:
    clang-tools-extra/trunk/clang-doc/stylesheets/
Modified:
    clang-tools-extra/trunk/clang-doc/Generators.cpp
    clang-tools-extra/trunk/clang-doc/Generators.h
    clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
    clang-tools-extra/trunk/clang-doc/MDGenerator.cpp
    clang-tools-extra/trunk/clang-doc/Representation.cpp
    clang-tools-extra/trunk/clang-doc/Representation.h
    clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp
    clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt
    clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
    clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt
    clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp
    clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h
    clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp

Modified: clang-tools-extra/trunk/clang-doc/Generators.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.cpp?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Generators.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/Generators.cpp Tue Aug  6 11:31:46 2019
@@ -57,6 +57,57 @@ std::string getTagType(TagTypeKind AS) {
   llvm_unreachable("Unknown TagTypeKind");
 }
 
+bool Generator::createResources(ClangDocContext &CDCtx) { return true; }
+
+// A function to add a reference to Info in Idx.
+// Given an Info X with the following namespaces: [B,A]; a reference to X will
+// be added in the children of a reference to B, which should be also a child of
+// a reference to A, where A is a child of Idx.
+//   Idx
+//    |-- A
+//        |--B
+//           |--X
+// If the references to the namespaces do not exist, they will be created. If
+// the references already exist, the same one will be used.
+void Generator::addInfoToIndex(Index &Idx, const doc::Info *Info) {
+  // Index pointer that will be moving through Idx until the first parent
+  // namespace of Info (where the reference has to be inserted) is found.
+  Index *I = &Idx;
+  // The Namespace vector includes the upper-most namespace at the end so the
+  // loop will start from the end to find each of the namespaces.
+  for (const auto &R : llvm::reverse(Info->Namespace)) {
+    // Look for the current namespace in the children of the index I is
+    // pointing.
+    auto It = std::find(I->Children.begin(), I->Children.end(), R.USR);
+    if (It != I->Children.end()) {
+      // If it is found, just change I to point the namespace refererence found.
+      I = &*It;
+    } else {
+      // If it is not found a new reference is created
+      I->Children.emplace_back(R.USR, R.Name, R.RefType, R.Path);
+      // I is updated with the reference of the new namespace reference
+      I = &I->Children.back();
+    }
+  }
+  // Look for Info in the vector where it is supposed to be; it could already
+  // exist if it is a parent namespace of an Info already passed to this
+  // function.
+  auto It = std::find(I->Children.begin(), I->Children.end(), Info->USR);
+  if (It == I->Children.end()) {
+    // If it is not in the vector it is inserted
+    I->Children.emplace_back(Info->USR, Info->extractName(), Info->IT,
+                             Info->Path);
+  } else {
+    // If it not in the vector we only check if Path and Name are not empty
+    // because if the Info was included by a namespace it may not have those
+    // values.
+    if (It->Path.empty())
+      It->Path = Info->Path;
+    if (It->Name.empty())
+      It->Name = Info->extractName();
+  }
+}
+
 // This anchor is used to force the linker to link in the generated object file
 // and thus register the generators.
 extern volatile int YAMLGeneratorAnchorSource;

Modified: clang-tools-extra/trunk/clang-doc/Generators.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.h?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Generators.h (original)
+++ clang-tools-extra/trunk/clang-doc/Generators.h Tue Aug  6 11:31:46 2019
@@ -28,7 +28,13 @@ public:
   // Write out the decl info in the specified format.
   virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
                                          const ClangDocContext &CDCtx) = 0;
-  virtual bool createResources(ClangDocContext CDCtx) = 0;
+  // This function writes a file with the index previously constructed.
+  // It can be overwritten by any of the inherited generators.
+  // If the override method wants to run this it should call
+  // Generator::createResources(CDCtx);
+  virtual bool createResources(ClangDocContext &CDCtx);
+
+  static void addInfoToIndex(Index &Idx, const doc::Info *Info);
 };
 
 typedef llvm::Registry<Generator> GeneratorRegistry;

Modified: clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp Tue Aug  6 11:31:46 2019
@@ -11,7 +11,9 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/JSON.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
 #include <string>
 
 using namespace llvm;
@@ -25,17 +27,19 @@ class HTMLTag {
 public:
   // Any other tag can be added if required
   enum TagType {
-    TAG_META,
-    TAG_TITLE,
+    TAG_A,
     TAG_DIV,
     TAG_H1,
     TAG_H2,
     TAG_H3,
-    TAG_P,
-    TAG_UL,
     TAG_LI,
-    TAG_A,
     TAG_LINK,
+    TAG_META,
+    TAG_P,
+    TAG_SCRIPT,
+    TAG_SPAN,
+    TAG_TITLE,
+    TAG_UL,
   };
 
   HTMLTag() = default;
@@ -106,15 +110,17 @@ bool HTMLTag::IsSelfClosing() const {
   case HTMLTag::TAG_META:
   case HTMLTag::TAG_LINK:
     return true;
-  case HTMLTag::TAG_TITLE:
+  case HTMLTag::TAG_A:
   case HTMLTag::TAG_DIV:
   case HTMLTag::TAG_H1:
   case HTMLTag::TAG_H2:
   case HTMLTag::TAG_H3:
+  case HTMLTag::TAG_LI:
   case HTMLTag::TAG_P:
+  case HTMLTag::TAG_SCRIPT:
+  case HTMLTag::TAG_SPAN:
+  case HTMLTag::TAG_TITLE:
   case HTMLTag::TAG_UL:
-  case HTMLTag::TAG_LI:
-  case HTMLTag::TAG_A:
     return false;
   }
   llvm_unreachable("Unhandled HTMLTag::TagType");
@@ -122,10 +128,8 @@ bool HTMLTag::IsSelfClosing() const {
 
 llvm::SmallString<16> HTMLTag::ToString() const {
   switch (Value) {
-  case HTMLTag::TAG_META:
-    return llvm::SmallString<16>("meta");
-  case HTMLTag::TAG_TITLE:
-    return llvm::SmallString<16>("title");
+  case HTMLTag::TAG_A:
+    return llvm::SmallString<16>("a");
   case HTMLTag::TAG_DIV:
     return llvm::SmallString<16>("div");
   case HTMLTag::TAG_H1:
@@ -134,16 +138,22 @@ llvm::SmallString<16> HTMLTag::ToString(
     return llvm::SmallString<16>("h2");
   case HTMLTag::TAG_H3:
     return llvm::SmallString<16>("h3");
-  case HTMLTag::TAG_P:
-    return llvm::SmallString<16>("p");
-  case HTMLTag::TAG_UL:
-    return llvm::SmallString<16>("ul");
   case HTMLTag::TAG_LI:
     return llvm::SmallString<16>("li");
-  case HTMLTag::TAG_A:
-    return llvm::SmallString<16>("a");
   case HTMLTag::TAG_LINK:
     return llvm::SmallString<16>("link");
+  case HTMLTag::TAG_META:
+    return llvm::SmallString<16>("meta");
+  case HTMLTag::TAG_P:
+    return llvm::SmallString<16>("p");
+  case HTMLTag::TAG_SCRIPT:
+    return llvm::SmallString<16>("script");
+  case HTMLTag::TAG_SPAN:
+    return llvm::SmallString<16>("span");
+  case HTMLTag::TAG_TITLE:
+    return llvm::SmallString<16>("title");
+  case HTMLTag::TAG_UL:
+    return llvm::SmallString<16>("ul");
   }
   llvm_unreachable("Unhandled HTMLTag::TagType");
 }
@@ -222,7 +232,7 @@ static SmallString<128> computeRelativeP
 
 // HTML generation
 
-std::vector<std::unique_ptr<TagNode>>
+static std::vector<std::unique_ptr<TagNode>>
 genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) {
   std::vector<std::unique_ptr<TagNode>> Out;
   for (const auto &FilePath : CDCtx.UserStylesheets) {
@@ -239,6 +249,19 @@ genStylesheetsHTML(StringRef InfoPath, c
   return Out;
 }
 
+static std::vector<std::unique_ptr<TagNode>>
+genJsScriptsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) {
+  std::vector<std::unique_ptr<TagNode>> Out;
+  for (const auto &FilePath : CDCtx.JsScripts) {
+    auto ScriptNode = llvm::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
+    SmallString<128> ScriptPath = computeRelativePath("", InfoPath);
+    llvm::sys::path::append(ScriptPath, llvm::sys::path::filename(FilePath));
+    ScriptNode->Attributes.try_emplace("src", ScriptPath);
+    Out.emplace_back(std::move(ScriptNode));
+  }
+  return Out;
+}
+
 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());
@@ -362,6 +385,28 @@ static std::unique_ptr<TagNode> writeFil
       "Defined at line " + std::to_string(L.LineNumber) + " of " + L.Filename);
 }
 
+static std::vector<std::unique_ptr<TagNode>>
+genCommonFileNodes(StringRef Title, StringRef InfoPath,
+                   const ClangDocContext &CDCtx) {
+  std::vector<std::unique_ptr<TagNode>> Out;
+  auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META);
+  MetaNode->Attributes.try_emplace("charset", "utf-8");
+  Out.emplace_back(std::move(MetaNode));
+  Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, Title));
+  std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
+      genStylesheetsHTML(InfoPath, CDCtx);
+  AppendVector(std::move(StylesheetsNodes), Out);
+  std::vector<std::unique_ptr<TagNode>> JsNodes =
+      genJsScriptsHTML(InfoPath, CDCtx);
+  AppendVector(std::move(JsNodes), Out);
+  // An empty <div> is generated but the index will be then rendered here
+  auto IndexNode = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
+  IndexNode->Attributes.try_emplace("id", "index");
+  IndexNode->Attributes.try_emplace("path", InfoPath);
+  Out.emplace_back(std::move(IndexNode));
+  return Out;
+}
+
 static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
   if (I.Kind == "FullComment") {
     auto FullComment = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
@@ -550,7 +595,7 @@ public:
 
   llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
                                  const ClangDocContext &CDCtx) override;
-  bool createResources(ClangDocContext CDCtx) override;
+  bool createResources(ClangDocContext &CDCtx) override;
 };
 
 const char *HTMLGenerator::Format = "html";
@@ -558,13 +603,7 @@ const char *HTMLGenerator::Format = "htm
 llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
                                               const ClangDocContext &CDCtx) {
   HTMLFile F;
-
-  auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META);
-  MetaNode->Attributes.try_emplace("charset", "utf-8");
-  F.Children.emplace_back(std::move(MetaNode));
-
   std::string InfoTitle;
-  Info CastedInfo;
   auto MainContentNode = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
   switch (I->IT) {
   case InfoType::IT_namespace: {
@@ -596,39 +635,91 @@ llvm::Error HTMLGenerator::generateDocFo
                                                llvm::inconvertibleErrorCode());
   }
 
-  F.Children.emplace_back(
-      llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, InfoTitle));
-  std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
-      genStylesheetsHTML(I->Path, CDCtx);
-  AppendVector(std::move(StylesheetsNodes), F.Children);
+  std::vector<std::unique_ptr<TagNode>> BasicNodes =
+      genCommonFileNodes(InfoTitle, I->Path, CDCtx);
+  AppendVector(std::move(BasicNodes), F.Children);
   F.Children.emplace_back(std::move(MainContentNode));
   F.Render(OS);
 
   return llvm::Error::success();
 }
 
-bool HTMLGenerator::createResources(ClangDocContext CDCtx) {
-  llvm::outs() << "Generating stylesheet for docs...\n";
-  for (const auto &FilePath : CDCtx.UserStylesheets) {
-    llvm::SmallString<128> StylesheetPathWrite;
-    llvm::sys::path::native(CDCtx.OutDirectory, StylesheetPathWrite);
-    llvm::sys::path::append(StylesheetPathWrite,
-                            llvm::sys::path::filename(FilePath));
-    llvm::SmallString<128> StylesheetPathRead;
-    llvm::sys::path::native(FilePath, StylesheetPathRead);
-    std::error_code OK;
-    std::error_code FileErr =
-        llvm::sys::fs::copy_file(StylesheetPathRead, StylesheetPathWrite);
-    if (FileErr != OK) {
-      llvm::errs() << "Error creating stylesheet file "
-                   << llvm::sys::path::filename(FilePath) << ": "
-                   << FileErr.message() << "\n";
-      return false;
-    }
+static std::string getRefType(InfoType IT) {
+  switch (IT) {
+  case InfoType::IT_default:
+    return "default";
+  case InfoType::IT_namespace:
+    return "namespace";
+  case InfoType::IT_record:
+    return "record";
+  case InfoType::IT_function:
+    return "function";
+  case InfoType::IT_enum:
+    return "enum";
+  }
+  llvm_unreachable("Unknown InfoType");
+}
+
+static bool SerializeIndex(ClangDocContext &CDCtx) {
+  std::error_code OK;
+  std::error_code FileErr;
+  llvm::SmallString<128> FilePath;
+  llvm::sys::path::native(CDCtx.OutDirectory, FilePath);
+  llvm::sys::path::append(FilePath, "index_json.js");
+  llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::F_None);
+  if (FileErr != OK) {
+    llvm::errs() << "Error creating index file: " << FileErr.message() << "\n";
+    return false;
+  }
+  CDCtx.Idx.sort();
+  llvm::json::OStream J(OS, 2);
+  std::function<void(Index)> IndexToJSON = [&](Index I) {
+    J.object([&] {
+      J.attribute("USR", toHex(llvm::toStringRef(I.USR)));
+      J.attribute("Name", I.Name);
+      J.attribute("RefType", getRefType(I.RefType));
+      J.attribute("Path", I.Path);
+      J.attributeArray("Children", [&] {
+        for (const Index &C : I.Children)
+          IndexToJSON(C);
+      });
+    });
+  };
+  OS << "var JsonIndex = `\n";
+  IndexToJSON(CDCtx.Idx);
+  OS << "`;\n";
+  return true;
+}
+
+static bool CopyFile(StringRef FilePath, StringRef OutDirectory) {
+  llvm::SmallString<128> PathWrite;
+  llvm::sys::path::native(OutDirectory, PathWrite);
+  llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
+  llvm::SmallString<128> PathRead;
+  llvm::sys::path::native(FilePath, PathRead);
+  std::error_code OK;
+  std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
+  if (FileErr != OK) {
+    llvm::errs() << "Error creating file "
+                 << llvm::sys::path::filename(FilePath) << ": "
+                 << FileErr.message() << "\n";
+    return false;
   }
   return true;
 }
 
+bool HTMLGenerator::createResources(ClangDocContext &CDCtx) {
+  if (!SerializeIndex(CDCtx))
+    return false;
+  for (const auto &FilePath : CDCtx.UserStylesheets)
+    if (!CopyFile(FilePath, CDCtx.OutDirectory))
+      return false;
+  for (const auto &FilePath : CDCtx.FilesToCopy)
+    if (!CopyFile(FilePath, CDCtx.OutDirectory))
+      return false;
+  return true;
+}
+
 static GeneratorRegistry::Add<HTMLGenerator> HTML(HTMLGenerator::Format,
                                                   "Generator for HTML output.");
 

Modified: clang-tools-extra/trunk/clang-doc/MDGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/MDGenerator.cpp?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/MDGenerator.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/MDGenerator.cpp Tue Aug  6 11:31:46 2019
@@ -252,7 +252,6 @@ public:
 
   llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
                                  const ClangDocContext &CDCtx) override;
-  bool createResources(ClangDocContext CDCtx) override { return true; }
 };
 
 const char *MDGenerator::Format = "md";

Modified: clang-tools-extra/trunk/clang-doc/Representation.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.cpp?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/Representation.cpp Tue Aug  6 11:31:46 2019
@@ -197,7 +197,7 @@ void FunctionInfo::merge(FunctionInfo &&
   SymbolInfo::merge(std::move(Other));
 }
 
-llvm::SmallString<16> Info::extractName() {
+llvm::SmallString<16> Info::extractName() const {
   if (!Name.empty())
     return Name;
 
@@ -229,5 +229,11 @@ llvm::SmallString<16> Info::extractName(
   return llvm::SmallString<16>("");
 }
 
+void Index::sort() {
+  std::sort(Children.begin(), Children.end());
+  for (auto &C : Children)
+    C.sort();
+}
+
 } // namespace doc
 } // namespace clang

Modified: clang-tools-extra/trunk/clang-doc/Representation.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.h?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.h (original)
+++ clang-tools-extra/trunk/clang-doc/Representation.h Tue Aug  6 11:31:46 2019
@@ -249,7 +249,7 @@ struct Info {
   void mergeBase(Info &&I);
   bool mergeable(const Info &Other);
 
-  llvm::SmallString<16> extractName();
+  llvm::SmallString<16> extractName() const;
 
   // Returns a reference to the parent scope (that is, the immediate parent
   // namespace or class in which this decl resides).
@@ -348,6 +348,19 @@ struct EnumInfo : public SymbolInfo {
   llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members.
 };
 
+struct Index : public Reference {
+  Index() = default;
+  Index(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)
+      : Reference(USR, Name, IT, Path) {}
+  // This is used to look for a USR in a vector of Indexes using std::find
+  bool operator==(const SymbolID &Other) const { return USR == Other; }
+  bool operator<(const Index &Other) const { return Name < Other.Name; }
+
+  std::vector<Index> Children;
+
+  void sort();
+};
+
 // TODO: Add functionality to include separate markdown pages.
 
 // A standalone function to call to merge a vector of infos into one.
@@ -357,10 +370,24 @@ llvm::Expected<std::unique_ptr<Info>>
 mergeInfos(std::vector<std::unique_ptr<Info>> &Values);
 
 struct ClangDocContext {
+  ClangDocContext() = default;
+  ClangDocContext(tooling::ExecutionContext *ECtx, bool PublicOnly,
+                  StringRef OutDirectory,
+                  std::vector<std::string> UserStylesheets,
+                  std::vector<std::string> JsScripts)
+      : ECtx(ECtx), PublicOnly(PublicOnly), OutDirectory(OutDirectory),
+        UserStylesheets(UserStylesheets), JsScripts(JsScripts) {}
   tooling::ExecutionContext *ECtx;
   bool PublicOnly;
   std::string OutDirectory;
+  // Path of CSS stylesheets that will be copied to OutDirectory and used to
+  // style all HTML files.
   std::vector<std::string> UserStylesheets;
+  // JavaScript files that will be imported in allHTML file.
+  std::vector<std::string> JsScripts;
+  // Other files that should be copied to OutDirectory, besides UserStylesheets.
+  std::vector<std::string> FilesToCopy;
+  Index Idx;
 };
 
 } // namespace doc

Modified: clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp Tue Aug  6 11:31:46 2019
@@ -246,7 +246,6 @@ public:
 
   llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
                                  const ClangDocContext &CDCtx) override;
-  bool createResources(ClangDocContext CDCtx) override { return true; }
 };
 
 const char *YAMLGenerator::Format = "yaml";

Added: clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css?rev=368070&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css (added)
+++ clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css Tue Aug  6 11:31:46 2019
@@ -0,0 +1,205 @@
+body,div {
+  margin: 0;
+  padding: 0;
+}
+
+body[no-overflow] {
+  overflow: hidden;
+}
+
+li>p:first-child {
+  margin-top: 0;
+}
+
+li>p:last-child {
+  margin-bottom: 0;
+}
+
+html {
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+}
+
+*,*::before,*::after {
+  -webkit-box-sizing: inherit;
+  box-sizing: inherit;
+}
+
+body,html {
+  color: #202124;
+  font: 400 16px/24px Roboto,sans-serif;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-font-smoothing: antialiased;
+  height: 100%;
+  margin: 36px;
+  -webkit-text-size-adjust: 100%;
+  -moz-text-size-adjust: 100%;
+  -ms-text-size-adjust: 100%;
+  text-size-adjust: 100%;
+}
+
+body[devsite-framebox] {
+  overflow: hidden;
+  padding: 20px;
+}
+
+body[sitemask--active] {
+  overflow: hidden;
+}
+
+p {
+  margin: 16px 0;
+  padding: 0;
+}
+
+:link,:visited {
+  color: #039be5;
+  outline: 0;
+  text-decoration: none;
+}
+
+ul {
+  margin: 0;
+  padding-left: 40px;
+}
+
+ul {
+  list-style: disc outside;
+}
+
+li,li p {
+  margin: 12px 0;
+  padding: 0;
+}
+
+*[visually-hidden] {
+  opacity: 0 !important;
+  pointer-events: none !important;
+  visibility: hidden !important;
+}
+
+*[hidden] {
+  display: none !important;
+}
+
+[render-hidden] {
+  display: inline !important;
+  position: absolute !important;
+  visibility: hidden !important;
+}
+
+*[no-scroll] {
+  overflow: hidden;
+}
+
+ at supports (display: flex) {
+  body[ready] .devsite-wrapper {
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -ms-flex-direction: column;
+    flex-direction: column;
+  }
+}
+
+ at media screen and (max-width: 840px) {
+  body[devsite-book-nav--open] {
+    overflow: hidden;
+  }
+}
+
+h1,h2,h3,h4,h5,h6 {
+  overflow: hidden;
+  padding: 0;
+  text-overflow: ellipsis;
+}
+
+h1 {
+  color: #80868b;
+  font: 300 34px/40px Roboto,sans-serif;
+  letter-spacing: -0.01em;
+  margin: 40px 0 20px;
+}
+
+[layout=docs] h2 {
+  border-bottom: 1px solid #e8eaed;
+  padding-bottom: 3px;
+}
+
+h2 {
+  font: 300 24px/32px Roboto,sans-serif;
+  letter-spacing: -0.01em;
+  margin: 40px 0 20px;
+}
+
+h3 {
+  font: 400 20px/32px Roboto,sans-serif;
+  margin: 32px 0 16px;
+}
+
+h4,h5,h6 {
+  margin: 32px 0 16px;
+}
+
+h4 {
+  font: 500 16px/24px Roboto,sans-serif;
+}
+
+h5 {
+  font: 700 14px/24px Roboto,sans-serif;
+}
+
+h6 {
+  font: 500 14px/24px Roboto,sans-serif;
+}
+
+h1+h1,h1+h2,h1+h3,h1+h4,h1+h5,h1+h6,h2+h1,h2+h2,h2+h3,h2+h4,h2+h5,h2+h6,h3+h1,h3+h2,h3+h3,h3+h4,h3+h5,h3+h6,h4+h1,h4+h2,h4+h3,h4+h4,h4+h5,h4+h6,h5+h1,h5+h2,h5+h3,h5+h4,h5+h5,h5+h6,h6+h1,h6+h2,h6+h3,h6+h4,h6+h5,h6+h6 {
+  margin-top: 0;
+}
+
+ at media screen and (max-width: 600px) {
+  h1 {
+    font: 300 24px/32px Roboto,sans-serif;
+  }
+}
+
+[scrollbars]::-webkit-scrollbar {
+  height: 8px;
+  width: 8px;
+}
+
+[scrollbars]::-webkit-scrollbar-thumb {
+  background: rgba(128,134,139,.26);
+  border-radius: 8px;
+}
+
+[no-horizontal-scrollbars]::-webkit-scrollbar {
+  height: 0;
+  width: 0;
+}
+
+[scrollbars]::-webkit-scrollbar-corner {
+  background: 0;
+}
+
+[background] h2 {
+  color: #fff;
+}
+
+ at media print {
+  body,  html,  :link,  :visited,  h1,  h2,  h3,  h4,  h5,  h6 {
+    color: #000 !important;
+    padding-left: 0 !important;
+    padding-right: 0 !important;
+  }
+
+  :link,  :visited {
+    text-decoration: underline;
+  }
+}
+
+ at page {
+  margin: .75in;
+}

Added: clang-tools-extra/trunk/clang-doc/assets/index.js
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/assets/index.js?rev=368070&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-doc/assets/index.js (added)
+++ clang-tools-extra/trunk/clang-doc/assets/index.js Tue Aug  6 11:31:46 2019
@@ -0,0 +1,81 @@
+// Append using posix-style a file name or directory to Base
+function append(Base, New) {
+  if (!New)
+    return Base;
+  if (Base)
+    Base += "/";
+  Base += New;
+  return Base;
+}
+
+// Get relative path to access FilePath from CurrentDirectory
+function computeRelativePath(FilePath, CurrentDirectory) {
+  var Path = FilePath;
+  while (Path) {
+    if (CurrentDirectory == Path)
+      return FilePath.substring(Path.length + 1);
+    Path = Path.substring(0, Path.lastIndexOf("/"));
+  }
+
+  var Dir = CurrentDirectory;
+  var Result = "";
+  while (Dir) {
+    if (Dir == FilePath)
+      break;
+    Dir = Dir.substring(0, Dir.lastIndexOf("/"));
+    Result = append(Result, "..")
+  }
+  Result = append(Result, FilePath.substring(Dir.length))
+  return Result;
+}
+
+function genLink(Ref, CurrentDirectory) {
+  var Path = computeRelativePath(Ref.Path, CurrentDirectory);
+  Path = append(Path, Ref.Name + ".html")
+  ANode = document.createElement("a");
+  ANode.setAttribute("href", Path);
+  var TextNode = document.createTextNode(Ref.Name);
+  ANode.appendChild(TextNode);
+  return ANode;
+}
+
+function genHTMLOfIndex(Index, CurrentDirectory) {
+  // Out will store the HTML elements that Index requires to be generated
+  var Out = [];
+  if (Index.Name) {
+    var SpanNode = document.createElement("span");
+    var TextNode = document.createTextNode(Index.Name);
+    SpanNode.appendChild(genLink(Index, CurrentDirectory));
+    Out.push(SpanNode);
+  }
+  if (Index.Children.length == 0)
+    return Out;
+  var UlNode = document.createElement("ul");
+  for (Child of Index.Children) {
+    var LiNode = document.createElement("li");
+    ChildNodes = genHTMLOfIndex(Child, CurrentDirectory);
+    for (Node of ChildNodes)
+      LiNode.appendChild(Node);
+    UlNode.appendChild(LiNode);
+  }
+  Out.push(UlNode);
+  return Out;
+}
+
+function createIndex(Index) {
+  // Get the DOM element where the index will be created
+  var IndexDiv = document.getElementById("index");
+  // Get the relative path of this file
+  CurrentDirectory = IndexDiv.getAttribute("path");
+  var IndexNodes = genHTMLOfIndex(Index, CurrentDirectory);
+  for (Node of IndexNodes)
+    IndexDiv.appendChild(Node);
+}
+
+// Runs after DOM loads
+document.addEventListener("DOMContentLoaded", function() {
+  // JsonIndex is a variable from another file that contains the index
+  // in JSON format
+  var Index = JSON.parse(JsonIndex);
+  createIndex(Index);
+});

Modified: clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt Tue Aug  6 11:31:46 2019
@@ -15,6 +15,10 @@ target_link_libraries(clang-doc
   clangToolingCore
   )
 
-install(FILES ../stylesheets/clang-doc-default-stylesheet.css
+install(FILES ../assets/clang-doc-default-stylesheet.css
+  DESTINATION share/clang
+  COMPONENT clang-doc)
+
+install(FILES ../assets/index.js
   DESTINATION share/clang
   COMPONENT clang-doc)

Modified: clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp Tue Aug  6 11:31:46 2019
@@ -215,18 +215,26 @@ int main(int argc, const char **argv) {
       Exec->get()->getExecutionContext(),
       PublicOnly,
       OutDirectory,
-      {UserStylesheets.begin(), UserStylesheets.end()}};
+      {UserStylesheets.begin(), UserStylesheets.end()},
+      {"index.js", "index_json.js"}};
 
   if (Format == "html") {
     void *MainAddr = (void *)(intptr_t)GetExecutablePath;
     std::string ClangDocPath = GetExecutablePath(argv[0], MainAddr);
+    llvm::SmallString<128> AssetsPath;
+    llvm::sys::path::native(ClangDocPath, AssetsPath);
+    AssetsPath = llvm::sys::path::parent_path(AssetsPath);
+    llvm::sys::path::append(AssetsPath, "..", "share", "clang");
     llvm::SmallString<128> DefaultStylesheet;
-    llvm::sys::path::native(ClangDocPath, DefaultStylesheet);
-    DefaultStylesheet = llvm::sys::path::parent_path(DefaultStylesheet);
+    llvm::sys::path::native(AssetsPath, DefaultStylesheet);
     llvm::sys::path::append(DefaultStylesheet,
-                            "../share/clang/clang-doc-default-stylesheet.css");
+                            "clang-doc-default-stylesheet.css");
+    llvm::SmallString<128> IndexJS;
+    llvm::sys::path::native(AssetsPath, IndexJS);
+    llvm::sys::path::append(IndexJS, "index.js");
     CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
                                  DefaultStylesheet.str());
+    CDCtx.FilesToCopy.emplace_back(IndexJS.str());
   }
 
   // Mapping phase
@@ -276,10 +284,14 @@ int main(int argc, const char **argv) {
       continue;
     }
 
+    // Add a reference to this Info in the Index
+    clang::doc::Generator::addInfoToIndex(CDCtx.Idx, I);
+
     if (auto Err = G->get()->generateDocForInfo(I, InfoOS, CDCtx))
       llvm::errs() << toString(std::move(Err)) << "\n";
   }
 
+  llvm::outs() << "Generating assets for docs...\n";
   if (!G->get()->createResources(CDCtx))
     return 1;
 

Modified: clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt Tue Aug  6 11:31:46 2019
@@ -12,6 +12,7 @@ include_directories(
 add_extra_unittest(ClangDocTests
   BitcodeTest.cpp
   ClangDocTest.cpp
+  GeneratorTest.cpp
   HTMLGeneratorTest.cpp
   MDGeneratorTest.cpp
   MergeTest.cpp

Modified: clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp Tue Aug  6 11:31:46 2019
@@ -63,6 +63,7 @@ void CheckCommentInfo(CommentInfo &Expec
 void CheckReference(Reference &Expected, Reference &Actual) {
   EXPECT_EQ(Expected.Name, Actual.Name);
   EXPECT_EQ(Expected.RefType, Actual.RefType);
+  EXPECT_EQ(Expected.Path, Actual.Path);
 }
 
 void CheckTypeInfo(TypeInfo *Expected, TypeInfo *Actual) {
@@ -180,5 +181,12 @@ void CheckRecordInfo(RecordInfo *Expecte
     CheckEnumInfo(&Expected->ChildEnums[Idx], &Actual->ChildEnums[Idx]);
 }
 
+void CheckIndex(Index &Expected, Index &Actual) {
+  CheckReference(Expected, Actual);
+  ASSERT_EQ(Expected.Children.size(), Actual.Children.size());
+  for (size_t Idx = 0; Idx < Actual.Children.size(); ++Idx)
+    CheckIndex(Expected.Children[Idx], Actual.Children[Idx]);
+}
+
 } // namespace doc
 } // namespace clang

Modified: clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h Tue Aug  6 11:31:46 2019
@@ -44,6 +44,8 @@ void CheckEnumInfo(EnumInfo *Expected, E
 void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual);
 void CheckRecordInfo(RecordInfo *Expected, RecordInfo *Actual);
 
+void CheckIndex(Index &Expected, Index &Actual);
+
 } // namespace doc
 } // namespace clang
 

Added: clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp?rev=368070&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp (added)
+++ clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp Tue Aug  6 11:31:46 2019
@@ -0,0 +1,74 @@
+//===-- clang-doc/GeneratorTest.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangDocTest.h"
+#include "Generators.h"
+#include "Representation.h"
+#include "Serialize.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace doc {
+
+TEST(GeneratorTest, emitIndex) {
+  Index Idx;
+  auto InfoA = llvm::make_unique<Info>();
+  InfoA->Name = "A";
+  InfoA->USR = serialize::hashUSR("1");
+  Generator::addInfoToIndex(Idx, InfoA.get());
+  auto InfoC = llvm::make_unique<Info>();
+  InfoC->Name = "C";
+  InfoC->USR = serialize::hashUSR("3");
+  Reference RefB = Reference("B");
+  RefB.USR = serialize::hashUSR("2");
+  InfoC->Namespace = {std::move(RefB)};
+  Generator::addInfoToIndex(Idx, InfoC.get());
+  auto InfoD = llvm::make_unique<Info>();
+  InfoD->Name = "D";
+  InfoD->USR = serialize::hashUSR("4");
+  auto InfoF = llvm::make_unique<Info>();
+  InfoF->Name = "F";
+  InfoF->USR = serialize::hashUSR("6");
+  Reference RefD = Reference("D");
+  RefD.USR = serialize::hashUSR("4");
+  Reference RefE = Reference("E");
+  RefE.USR = serialize::hashUSR("5");
+  InfoF->Namespace = {std::move(RefE), std::move(RefD)};
+  Generator::addInfoToIndex(Idx, InfoF.get());
+  auto InfoG = llvm::make_unique<Info>(InfoType::IT_namespace);
+  Generator::addInfoToIndex(Idx, InfoG.get());
+
+  Index ExpectedIdx;
+  Index IndexA;
+  IndexA.Name = "A";
+  ExpectedIdx.Children.emplace_back(std::move(IndexA));
+  Index IndexB;
+  IndexB.Name = "B";
+  Index IndexC;
+  IndexC.Name = "C";
+  IndexB.Children.emplace_back(std::move(IndexC));
+  ExpectedIdx.Children.emplace_back(std::move(IndexB));
+  Index IndexD;
+  IndexD.Name = "D";
+  Index IndexE;
+  IndexE.Name = "E";
+  Index IndexF;
+  IndexF.Name = "F";
+  IndexE.Children.emplace_back(std::move(IndexF));
+  IndexD.Children.emplace_back(std::move(IndexE));
+  ExpectedIdx.Children.emplace_back(std::move(IndexD));
+  Index IndexG;
+  IndexG.Name = "GlobalNamespace";
+  IndexG.RefType = InfoType::IT_namespace;
+  ExpectedIdx.Children.emplace_back(std::move(IndexG));
+
+  CheckIndex(ExpectedIdx, Idx);
+}
+
+} // namespace doc
+} // namespace clang

Modified: clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp?rev=368070&r1=368069&r2=368070&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp Tue Aug  6 11:31:46 2019
@@ -28,6 +28,7 @@ getClangDocContext(std::vector<std::stri
   CDCtx.UserStylesheets.insert(
       CDCtx.UserStylesheets.begin(),
       "../share/clang/clang-doc-default-stylesheet.css");
+  CDCtx.JsScripts.emplace_back("index.js");
   return CDCtx;
 }
 
@@ -56,6 +57,8 @@ TEST(HTMLGeneratorTest, emitNamespaceHTM
 <title>namespace Namespace</title>
 <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
 <link rel="stylesheet" href="user-provided-stylesheet.css"/>
+<script src="index.js"></script>
+<div id="index" path=""></div>
 <div>
   <h1>namespace Namespace</h1>
   <h2>Namespaces</h2>
@@ -114,6 +117,8 @@ TEST(HTMLGeneratorTest, emitRecordHTML)
 <meta charset="utf-8"/>
 <title>class r</title>
 <link rel="stylesheet" href="../../../clang-doc-default-stylesheet.css"/>
+<script src="../../../index.js"></script>
+<div id="index" path="X/Y/Z"></div>
 <div>
   <h1>class r</h1>
   <p>Defined at line 10 of test.cpp</p>
@@ -175,6 +180,8 @@ TEST(HTMLGeneratorTest, emitFunctionHTML
 <meta charset="utf-8"/>
 <title></title>
 <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
+<script src="index.js"></script>
+<div id="index" path=""></div>
 <div>
   <h3>f</h3>
   <p>
@@ -212,6 +219,8 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
 <meta charset="utf-8"/>
 <title></title>
 <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
+<script src="index.js"></script>
+<div id="index" path=""></div>
 <div>
   <h3>enum class e</h3>
   <ul>
@@ -281,6 +290,8 @@ TEST(HTMLGeneratorTest, emitCommentHTML)
 <meta charset="utf-8"/>
 <title></title>
 <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
+<script src="index.js"></script>
+<div id="index" path=""></div>
 <div>
   <h3>f</h3>
   <p>void f(int I, int J)</p>




More information about the cfe-commits mailing list