clang-tools  14.0.0git
MDGenerator.cpp
Go to the documentation of this file.
1 //===-- MDGenerator.cpp - Markdown Generator --------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Generators.h"
10 #include "Representation.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/Support/FileSystem.h"
13 #include "llvm/Support/Path.h"
14 #include <string>
15 
16 using namespace llvm;
17 
18 namespace clang {
19 namespace doc {
20 
21 // Markdown generation
22 
23 static std::string genItalic(const Twine &Text) {
24  return "*" + Text.str() + "*";
25 }
26 
27 static std::string genEmphasis(const Twine &Text) {
28  return "**" + Text.str() + "**";
29 }
30 
31 static std::string
32 genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
33  std::string Buffer;
34  llvm::raw_string_ostream Stream(Buffer);
35  for (const auto &R : Refs) {
36  if (&R != Refs.begin())
37  Stream << ", ";
38  Stream << R.Name;
39  }
40  return Stream.str();
41 }
42 
43 static void writeLine(const Twine &Text, raw_ostream &OS) {
44  OS << Text << "\n\n";
45 }
46 
47 static void writeNewLine(raw_ostream &OS) { OS << "\n\n"; }
48 
49 static void writeHeader(const Twine &Text, unsigned int Num, raw_ostream &OS) {
50  OS << std::string(Num, '#') + " " + Text << "\n\n";
51 }
52 
53 static void writeFileDefinition(const ClangDocContext &CDCtx, const Location &L,
54  raw_ostream &OS) {
55 
56  if (!CDCtx.RepositoryUrl) {
57  OS << "*Defined at " << L.Filename << "#" << std::to_string(L.LineNumber)
58  << "*";
59  } else {
60  OS << "*Defined at [" << L.Filename << "#" << std::to_string(L.LineNumber)
61  << "](" << StringRef{CDCtx.RepositoryUrl.getValue()}
62  << llvm::sys::path::relative_path(L.Filename) << "#"
63  << std::to_string(L.LineNumber) << ")"
64  << "*";
65  }
66  OS << "\n\n";
67 }
68 
69 static void writeDescription(const CommentInfo &I, raw_ostream &OS) {
70  if (I.Kind == "FullComment") {
71  for (const auto &Child : I.Children)
72  writeDescription(*Child, OS);
73  } else if (I.Kind == "ParagraphComment") {
74  for (const auto &Child : I.Children)
75  writeDescription(*Child, OS);
77  } else if (I.Kind == "BlockCommandComment") {
78  OS << genEmphasis(I.Name);
79  for (const auto &Child : I.Children)
80  writeDescription(*Child, OS);
81  } else if (I.Kind == "InlineCommandComment") {
82  OS << genEmphasis(I.Name) << " " << I.Text;
83  } else if (I.Kind == "ParamCommandComment") {
84  std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
85  OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
86  } else if (I.Kind == "TParamCommandComment") {
87  std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
88  OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
89  } else if (I.Kind == "VerbatimBlockComment") {
90  for (const auto &Child : I.Children)
91  writeDescription(*Child, OS);
92  } else if (I.Kind == "VerbatimBlockLineComment") {
93  OS << I.Text;
95  } else if (I.Kind == "VerbatimLineComment") {
96  OS << I.Text;
98  } else if (I.Kind == "HTMLStartTagComment") {
99  if (I.AttrKeys.size() != I.AttrValues.size())
100  return;
101  std::string Buffer;
102  llvm::raw_string_ostream Attrs(Buffer);
103  for (unsigned Idx = 0; Idx < I.AttrKeys.size(); ++Idx)
104  Attrs << " \"" << I.AttrKeys[Idx] << "=" << I.AttrValues[Idx] << "\"";
105 
106  std::string CloseTag = I.SelfClosing ? "/>" : ">";
107  writeLine("<" + I.Name + Attrs.str() + CloseTag, OS);
108  } else if (I.Kind == "HTMLEndTagComment") {
109  writeLine("</" + I.Name + ">", OS);
110  } else if (I.Kind == "TextComment") {
111  OS << I.Text;
112  } else {
113  OS << "Unknown comment kind: " << I.Kind << ".\n\n";
114  }
115 }
116 
117 static void writeNameLink(const StringRef &CurrentPath, const Reference &R,
118  llvm::raw_ostream &OS) {
119  llvm::SmallString<64> Path = R.getRelativeFilePath(CurrentPath);
120  // Paths in Markdown use POSIX separators.
121  llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
122  llvm::sys::path::append(Path, llvm::sys::path::Style::posix,
123  R.getFileBaseName() + ".md");
124  OS << "[" << R.Name << "](" << Path << ")";
125 }
126 
127 static void genMarkdown(const ClangDocContext &CDCtx, const EnumInfo &I,
128  llvm::raw_ostream &OS) {
129  if (I.Scoped)
130  writeLine("| enum class " + I.Name + " |", OS);
131  else
132  writeLine("| enum " + I.Name + " |", OS);
133  writeLine("--", OS);
134 
135  std::string Buffer;
136  llvm::raw_string_ostream Members(Buffer);
137  if (!I.Members.empty())
138  for (const auto &N : I.Members)
139  Members << "| " << N << " |\n";
140  writeLine(Members.str(), OS);
141  if (I.DefLoc)
142  writeFileDefinition(CDCtx, I.DefLoc.getValue(), OS);
143 
144  for (const auto &C : I.Description)
146 }
147 
148 static void genMarkdown(const ClangDocContext &CDCtx, const FunctionInfo &I,
149  llvm::raw_ostream &OS) {
150  std::string Buffer;
151  llvm::raw_string_ostream Stream(Buffer);
152  bool First = true;
153  for (const auto &N : I.Params) {
154  if (!First)
155  Stream << ", ";
156  Stream << N.Type.Name + " " + N.Name;
157  First = false;
158  }
159  writeHeader(I.Name, 3, OS);
160  std::string Access = getAccessSpelling(I.Access).str();
161  if (Access != "")
162  writeLine(genItalic(Access + " " + I.ReturnType.Type.Name + " " + I.Name +
163  "(" + Stream.str() + ")"),
164  OS);
165  else
166  writeLine(genItalic(I.ReturnType.Type.Name + " " + I.Name + "(" +
167  Stream.str() + ")"),
168  OS);
169  if (I.DefLoc)
170  writeFileDefinition(CDCtx, I.DefLoc.getValue(), OS);
171 
172  for (const auto &C : I.Description)
174 }
175 
176 static void genMarkdown(const ClangDocContext &CDCtx, const NamespaceInfo &I,
177  llvm::raw_ostream &OS) {
178  if (I.Name == "")
179  writeHeader("Global Namespace", 1, OS);
180  else
181  writeHeader("namespace " + I.Name, 1, OS);
182  writeNewLine(OS);
183 
184  if (!I.Description.empty()) {
185  for (const auto &C : I.Description)
187  writeNewLine(OS);
188  }
189 
190  llvm::SmallString<64> BasePath = I.getRelativeFilePath("");
191 
192  if (!I.ChildNamespaces.empty()) {
193  writeHeader("Namespaces", 2, OS);
194  for (const auto &R : I.ChildNamespaces) {
195  OS << "* ";
196  writeNameLink(BasePath, R, OS);
197  OS << "\n";
198  }
199  writeNewLine(OS);
200  }
201 
202  if (!I.ChildRecords.empty()) {
203  writeHeader("Records", 2, OS);
204  for (const auto &R : I.ChildRecords) {
205  OS << "* ";
206  writeNameLink(BasePath, R, OS);
207  OS << "\n";
208  }
209  writeNewLine(OS);
210  }
211 
212  if (!I.ChildFunctions.empty()) {
213  writeHeader("Functions", 2, OS);
214  for (const auto &F : I.ChildFunctions)
215  genMarkdown(CDCtx, F, OS);
216  writeNewLine(OS);
217  }
218  if (!I.ChildEnums.empty()) {
219  writeHeader("Enums", 2, OS);
220  for (const auto &E : I.ChildEnums)
221  genMarkdown(CDCtx, E, OS);
222  writeNewLine(OS);
223  }
224 }
225 
226 static void genMarkdown(const ClangDocContext &CDCtx, const RecordInfo &I,
227  llvm::raw_ostream &OS) {
228  writeHeader(getTagType(I.TagType) + " " + I.Name, 1, OS);
229  if (I.DefLoc)
230  writeFileDefinition(CDCtx, I.DefLoc.getValue(), OS);
231 
232  if (!I.Description.empty()) {
233  for (const auto &C : I.Description)
235  writeNewLine(OS);
236  }
237 
238  std::string Parents = genReferenceList(I.Parents);
239  std::string VParents = genReferenceList(I.VirtualParents);
240  if (!Parents.empty() || !VParents.empty()) {
241  if (Parents.empty())
242  writeLine("Inherits from " + VParents, OS);
243  else if (VParents.empty())
244  writeLine("Inherits from " + Parents, OS);
245  else
246  writeLine("Inherits from " + Parents + ", " + VParents, OS);
247  writeNewLine(OS);
248  }
249 
250  if (!I.Members.empty()) {
251  writeHeader("Members", 2, OS);
252  for (const auto &Member : I.Members) {
253  std::string Access = getAccessSpelling(Member.Access).str();
254  if (Access != "")
255  writeLine(Access + " " + Member.Type.Name + " " + Member.Name, OS);
256  else
257  writeLine(Member.Type.Name + " " + Member.Name, OS);
258  }
259  writeNewLine(OS);
260  }
261 
262  if (!I.ChildRecords.empty()) {
263  writeHeader("Records", 2, OS);
264  for (const auto &R : I.ChildRecords)
265  writeLine(R.Name, OS);
266  writeNewLine(OS);
267  }
268  if (!I.ChildFunctions.empty()) {
269  writeHeader("Functions", 2, OS);
270  for (const auto &F : I.ChildFunctions)
271  genMarkdown(CDCtx, F, OS);
272  writeNewLine(OS);
273  }
274  if (!I.ChildEnums.empty()) {
275  writeHeader("Enums", 2, OS);
276  for (const auto &E : I.ChildEnums)
277  genMarkdown(CDCtx, E, OS);
278  writeNewLine(OS);
279  }
280 }
281 
282 static void serializeReference(llvm::raw_fd_ostream &OS, Index &I, int Level) {
283  // Write out the heading level starting at ##
284  OS << "##" << std::string(Level, '#') << " ";
285  writeNameLink("", I, OS);
286  OS << "\n";
287 }
288 
289 static llvm::Error serializeIndex(ClangDocContext &CDCtx) {
290  std::error_code FileErr;
291  llvm::SmallString<128> FilePath;
292  llvm::sys::path::native(CDCtx.OutDirectory, FilePath);
293  llvm::sys::path::append(FilePath, "all_files.md");
294  llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_None);
295  if (FileErr)
296  return llvm::createStringError(llvm::inconvertibleErrorCode(),
297  "error creating index file: " +
298  FileErr.message());
299 
300  CDCtx.Idx.sort();
301  OS << "# All Files";
302  if (!CDCtx.ProjectName.empty())
303  OS << " for " << CDCtx.ProjectName;
304  OS << "\n\n";
305 
306  for (auto C : CDCtx.Idx.Children)
307  serializeReference(OS, C, 0);
308 
309  return llvm::Error::success();
310 }
311 
312 static llvm::Error genIndex(ClangDocContext &CDCtx) {
313  std::error_code FileErr;
314  llvm::SmallString<128> FilePath;
315  llvm::sys::path::native(CDCtx.OutDirectory, FilePath);
316  llvm::sys::path::append(FilePath, "index.md");
317  llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_None);
318  if (FileErr)
319  return llvm::createStringError(llvm::inconvertibleErrorCode(),
320  "error creating index file: " +
321  FileErr.message());
322  CDCtx.Idx.sort();
323  OS << "# " << CDCtx.ProjectName << " C/C++ Reference\n\n";
324  for (auto C : CDCtx.Idx.Children) {
325  if (!C.Children.empty()) {
326  const char *Type;
327  switch (C.RefType) {
328  case InfoType::IT_namespace:
329  Type = "Namespace";
330  break;
331  case InfoType::IT_record:
332  Type = "Type";
333  break;
334  case InfoType::IT_enum:
335  Type = "Enum";
336  break;
337  case InfoType::IT_function:
338  Type = "Function";
339  break;
340  case InfoType::IT_default:
341  Type = "Other";
342  }
343  OS << "* " << Type << ": [" << C.Name << "](";
344  if (!C.Path.empty())
345  OS << C.Path << "/";
346  OS << C.Name << ")\n";
347  }
348  }
349  return llvm::Error::success();
350 }
351 /// Generator for Markdown documentation.
352 class MDGenerator : public Generator {
353 public:
354  static const char *Format;
355 
356  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
357  const ClangDocContext &CDCtx) override;
358  llvm::Error createResources(ClangDocContext &CDCtx) override;
359 };
360 
361 const char *MDGenerator::Format = "md";
362 
363 llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
364  const ClangDocContext &CDCtx) {
365  switch (I->IT) {
366  case InfoType::IT_namespace:
367  genMarkdown(CDCtx, *static_cast<clang::doc::NamespaceInfo *>(I), OS);
368  break;
369  case InfoType::IT_record:
370  genMarkdown(CDCtx, *static_cast<clang::doc::RecordInfo *>(I), OS);
371  break;
372  case InfoType::IT_enum:
373  genMarkdown(CDCtx, *static_cast<clang::doc::EnumInfo *>(I), OS);
374  break;
375  case InfoType::IT_function:
376  genMarkdown(CDCtx, *static_cast<clang::doc::FunctionInfo *>(I), OS);
377  break;
378  case InfoType::IT_default:
379  return createStringError(llvm::inconvertibleErrorCode(),
380  "unexpected InfoType");
381  }
382  return llvm::Error::success();
383 }
384 
385 llvm::Error MDGenerator::createResources(ClangDocContext &CDCtx) {
386  // Write an all_files.md
387  auto Err = serializeIndex(CDCtx);
388  if (Err)
389  return Err;
390 
391  // Generate the index page.
392  Err = genIndex(CDCtx);
393  if (Err)
394  return Err;
395 
396  return llvm::Error::success();
397 }
398 
399 static GeneratorRegistry::Add<MDGenerator> MD(MDGenerator::Format,
400  "Generator for MD output.");
401 
402 // This anchor is used to force the linker to link in the generated object
403 // file and thus register the generator.
404 volatile int MDGeneratorAnchorSource = 0;
405 
406 } // namespace doc
407 } // namespace clang
clang::doc::MDGeneratorAnchorSource
volatile int MDGeneratorAnchorSource
Definition: MDGenerator.cpp:404
clang::doc::genMarkdown
static void genMarkdown(const ClangDocContext &CDCtx, const RecordInfo &I, llvm::raw_ostream &OS)
Definition: MDGenerator.cpp:226
llvm
Some operations such as code completion produce a set of candidates.
Definition: YAMLGenerator.cpp:28
clang::doc::Info::Description
std::vector< CommentInfo > Description
Definition: Representation.h:262
clang::doc::NamespaceInfo::ChildEnums
std::vector< EnumInfo > ChildEnums
Definition: Representation.h:300
clang::doc::Reference::getFileBaseName
llvm::SmallString< 16 > getFileBaseName() const
Returns the basename that should be used for this Reference.
Definition: Representation.cpp:144
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
clang::doc::writeNameLink
static void writeNameLink(const StringRef &CurrentPath, const Reference &R, llvm::raw_ostream &OS)
Definition: MDGenerator.cpp:117
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::doc::NamespaceInfo::ChildFunctions
std::vector< FunctionInfo > ChildFunctions
Definition: Representation.h:299
Refs
RefSlab Refs
Definition: SymbolCollectorTests.cpp:311
clang::doc::Info::Name
SmallString< 16 > Name
Definition: Representation.h:259
clang::doc::Index
Definition: Representation.h:401
clang::doc::MD
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
clang::doc::ClangDocContext::Idx
Index Idx
Definition: Representation.h:449
clang::doc::FunctionInfo
Definition: Representation.h:319
clang::doc::NamespaceInfo::ChildNamespaces
std::vector< Reference > ChildNamespaces
Definition: Representation.h:297
clang::doc::getTagType
std::string getTagType(TagTypeKind AS)
Definition: Generators.cpp:29
clang::doc::writeLine
static void writeLine(const Twine &Text, raw_ostream &OS)
Definition: MDGenerator.cpp:43
clang::doc::CommentInfo
Definition: Representation.h:46
clang::doc::Reference::Name
SmallString< 16 > Name
Definition: Representation.h:145
clang::doc::ClangDocContext::RepositoryUrl
llvm::Optional< std::string > RepositoryUrl
Definition: Representation.h:441
clang::doc::EnumInfo
Definition: Representation.h:390
Text
std::string Text
Definition: HTMLGenerator.cpp:80
clang::doc::CommentInfo::Kind
SmallString< 16 > Kind
Definition: Representation.h:92
Representation.h
clang::doc::CommentInfo::Direction
SmallString< 8 > Direction
Definition: Representation.h:99
clang::doc::CommentInfo::Explicit
bool Explicit
Definition: Representation.h:103
clang::doc::RecordInfo::VirtualParents
llvm::SmallVector< Reference, 4 > VirtualParents
Definition: Representation.h:359
clang::doc::CommentInfo::Name
SmallString< 16 > Name
Definition: Representation.h:98
clang::doc::RecordInfo::Members
llvm::SmallVector< MemberTypeInfo, 4 > Members
Definition: Representation.h:354
clang::doc::ClangDocContext::ProjectName
std::string ProjectName
Definition: Representation.h:434
clang::doc::Location
Definition: Representation.h:215
clang::doc::CommentInfo::ParamName
SmallString< 16 > ParamName
Definition: Representation.h:100
clang::doc::serializeIndex
static llvm::Error serializeIndex(ClangDocContext &CDCtx)
Definition: MDGenerator.cpp:289
clang::doc::CommentInfo::Children
std::vector< std::unique_ptr< CommentInfo > > Children
Definition: Representation.h:112
clang::doc::CommentInfo::AttrKeys
llvm::SmallVector< SmallString< 16 >, 4 > AttrKeys
Definition: Representation.h:106
clang::doc::EnumInfo::Members
llvm::SmallVector< SmallString< 16 >, 4 > Members
Definition: Representation.h:398
clang::doc::CommentInfo::Text
SmallString< 64 > Text
Definition: Representation.h:97
clang::doc::ClangDocContext::OutDirectory
std::string OutDirectory
Definition: Representation.h:436
clang::doc::ClangDocContext
Definition: Representation.h:426
clang::doc::writeHeader
static void writeHeader(const Twine &Text, unsigned int Num, raw_ostream &OS)
Definition: MDGenerator.cpp:49
clang::doc::genReferenceList
static std::string genReferenceList(const llvm::SmallVectorImpl< Reference > &Refs)
Definition: MDGenerator.cpp:32
clang::doc::RecordInfo::Parents
llvm::SmallVector< Reference, 4 > Parents
Definition: Representation.h:355
clang::doc::Reference::getRelativeFilePath
llvm::SmallString< 64 > getRelativeFilePath(const StringRef &CurrentPath) const
Returns the path for this Reference relative to CurrentPath.
Definition: Representation.cpp:140
clang::doc::genItalic
static std::string genItalic(const Twine &Text)
Definition: MDGenerator.cpp:23
clang::doc::serializeReference
static void serializeReference(llvm::raw_fd_ostream &OS, Index &I, int Level)
Definition: MDGenerator.cpp:282
clang::doc::FunctionInfo::Access
AccessSpecifier Access
Definition: Representation.h:333
clang::doc::writeFileDefinition
static void writeFileDefinition(const ClangDocContext &CDCtx, const Location &L, raw_ostream &OS)
Definition: MDGenerator.cpp:53
clang::doc::FunctionInfo::Params
llvm::SmallVector< FieldTypeInfo, 4 > Params
Definition: Representation.h:328
clang::doc::RecordInfo
Definition: Representation.h:339
clang::doc::TypeInfo::Type
Reference Type
Definition: Representation.h:169
clang::doc::writeDescription
static void writeDescription(const CommentInfo &I, raw_ostream &OS)
Definition: MDGenerator.cpp:69
clang::doc::RecordInfo::ChildRecords
std::vector< Reference > ChildRecords
Definition: Representation.h:368
clang::doc::Info
A base struct for Infos.
Definition: Representation.h:243
clang::doc::Generator
Definition: Generators.h:24
clang::doc::Reference
Definition: Representation.h:115
clang::doc::Info::IT
const InfoType IT
Definition: Representation.h:258
clang::doc::CommentInfo::SelfClosing
bool SelfClosing
Definition: Representation.h:102
clang::doc::RecordInfo::ChildFunctions
std::vector< FunctionInfo > ChildFunctions
Definition: Representation.h:369
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::doc::FunctionInfo::ReturnType
TypeInfo ReturnType
Definition: Representation.h:327
clang::doc::genEmphasis
static std::string genEmphasis(const Twine &Text)
Definition: MDGenerator.cpp:27
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::doc::NamespaceInfo
Definition: Representation.h:283
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:163
clang::doc::NamespaceInfo::ChildRecords
std::vector< Reference > ChildRecords
Definition: Representation.h:298
clang::doc::genIndex
static llvm::Error genIndex(ClangDocContext &CDCtx)
Definition: MDGenerator.cpp:312
clang::doc::MDGenerator::Format
static const char * Format
Definition: MDGenerator.cpp:354
clang::doc::RecordInfo::TagType
TagTypeKind TagType
Definition: Representation.h:349
clang::doc::MDGenerator
Generator for Markdown documentation.
Definition: MDGenerator.cpp:352
clang::doc::CommentInfo::AttrValues
llvm::SmallVector< SmallString< 16 >, 4 > AttrValues
Definition: Representation.h:108
Generators.h
clang::doc::RecordInfo::ChildEnums
std::vector< EnumInfo > ChildEnums
Definition: Representation.h:370
clang::doc::Index::sort
void sort()
Definition: Representation.cpp:316
clang::doc::SymbolInfo::DefLoc
llvm::Optional< Location > DefLoc
Definition: Representation.h:313
clang::doc::writeNewLine
static void writeNewLine(raw_ostream &OS)
Definition: MDGenerator.cpp:47
clang::doc::Info::getRelativeFilePath
llvm::SmallString< 64 > getRelativeFilePath(const StringRef &CurrentPath) const
Returns the file path for this Info relative to CurrentPath.
Definition: Representation.cpp:152
clang::doc::EnumInfo::Scoped
bool Scoped
Definition: Representation.h:396
Path
std::vector< HeaderHandle > Path
Definition: PreprocessorTracker.cpp:525
clang::doc::Index::Children
std::vector< Index > Children
Definition: Representation.h:413