clang-tools  10.0.0
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 Location &L, raw_ostream &OS) {
54  OS << genItalic("Defined at line " + std::to_string(L.LineNumber) + " of " +
55  L.Filename)
56  << "\n\n";
57 }
58 
59 static void writeDescription(const CommentInfo &I, raw_ostream &OS) {
60  if (I.Kind == "FullComment") {
61  for (const auto &Child : I.Children)
62  writeDescription(*Child, OS);
63  } else if (I.Kind == "ParagraphComment") {
64  for (const auto &Child : I.Children)
65  writeDescription(*Child, OS);
66  writeNewLine(OS);
67  } else if (I.Kind == "BlockCommandComment") {
68  OS << genEmphasis(I.Name);
69  for (const auto &Child : I.Children)
70  writeDescription(*Child, OS);
71  } else if (I.Kind == "InlineCommandComment") {
72  OS << genEmphasis(I.Name) << " " << I.Text;
73  } else if (I.Kind == "ParamCommandComment") {
74  std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
75  OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
76  } else if (I.Kind == "TParamCommandComment") {
77  std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
78  OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
79  } else if (I.Kind == "VerbatimBlockComment") {
80  for (const auto &Child : I.Children)
81  writeDescription(*Child, OS);
82  } else if (I.Kind == "VerbatimBlockLineComment") {
83  OS << I.Text;
84  writeNewLine(OS);
85  } else if (I.Kind == "VerbatimLineComment") {
86  OS << I.Text;
87  writeNewLine(OS);
88  } else if (I.Kind == "HTMLStartTagComment") {
89  if (I.AttrKeys.size() != I.AttrValues.size())
90  return;
91  std::string Buffer;
92  llvm::raw_string_ostream Attrs(Buffer);
93  for (unsigned Idx = 0; Idx < I.AttrKeys.size(); ++Idx)
94  Attrs << " \"" << I.AttrKeys[Idx] << "=" << I.AttrValues[Idx] << "\"";
95 
96  std::string CloseTag = I.SelfClosing ? "/>" : ">";
97  writeLine("<" + I.Name + Attrs.str() + CloseTag, OS);
98  } else if (I.Kind == "HTMLEndTagComment") {
99  writeLine("</" + I.Name + ">", OS);
100  } else if (I.Kind == "TextComment") {
101  OS << I.Text;
102  } else {
103  OS << "Unknown comment kind: " << I.Kind << ".\n\n";
104  }
105 }
106 
107 static void genMarkdown(const EnumInfo &I, llvm::raw_ostream &OS) {
108  if (I.Scoped)
109  writeLine("| enum class " + I.Name + " |", OS);
110  else
111  writeLine("| enum " + I.Name + " |", OS);
112  writeLine("--", OS);
113 
114  std::string Buffer;
115  llvm::raw_string_ostream Members(Buffer);
116  if (!I.Members.empty())
117  for (const auto &N : I.Members)
118  Members << "| " << N << " |\n";
119  writeLine(Members.str(), OS);
120  if (I.DefLoc)
121  writeFileDefinition(I.DefLoc.getValue(), OS);
122 
123  for (const auto &C : I.Description)
124  writeDescription(C, OS);
125 }
126 
127 static void genMarkdown(const FunctionInfo &I, llvm::raw_ostream &OS) {
128  std::string Buffer;
129  llvm::raw_string_ostream Stream(Buffer);
130  bool First = true;
131  for (const auto &N : I.Params) {
132  if (!First)
133  Stream << ", ";
134  Stream << N.Type.Name + " " + N.Name;
135  First = false;
136  }
137  writeHeader(I.Name, 3, OS);
138  std::string Access = getAccess(I.Access);
139  if (Access != "")
140  writeLine(genItalic(Access + " " + I.ReturnType.Type.Name + " " + I.Name +
141  "(" + Stream.str() + ")"),
142  OS);
143  else
144  writeLine(genItalic(I.ReturnType.Type.Name + " " + I.Name + "(" +
145  Stream.str() + ")"),
146  OS);
147  if (I.DefLoc)
148  writeFileDefinition(I.DefLoc.getValue(), OS);
149 
150  for (const auto &C : I.Description)
151  writeDescription(C, OS);
152 }
153 
154 static void genMarkdown(const NamespaceInfo &I, llvm::raw_ostream &OS) {
155  if (I.Name == "")
156  writeHeader("Global Namespace", 1, OS);
157  else
158  writeHeader("namespace " + I.Name, 1, OS);
159  writeNewLine(OS);
160 
161  if (!I.Description.empty()) {
162  for (const auto &C : I.Description)
163  writeDescription(C, OS);
164  writeNewLine(OS);
165  }
166 
167  if (!I.ChildNamespaces.empty()) {
168  writeHeader("Namespaces", 2, OS);
169  for (const auto &R : I.ChildNamespaces)
170  writeLine(R.Name, OS);
171  writeNewLine(OS);
172  }
173  if (!I.ChildRecords.empty()) {
174  writeHeader("Records", 2, OS);
175  for (const auto &R : I.ChildRecords)
176  writeLine(R.Name, OS);
177  writeNewLine(OS);
178  }
179  if (!I.ChildFunctions.empty()) {
180  writeHeader("Functions", 2, OS);
181  for (const auto &F : I.ChildFunctions)
182  genMarkdown(F, OS);
183  writeNewLine(OS);
184  }
185  if (!I.ChildEnums.empty()) {
186  writeHeader("Enums", 2, OS);
187  for (const auto &E : I.ChildEnums)
188  genMarkdown(E, OS);
189  writeNewLine(OS);
190  }
191 }
192 
193 static void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS) {
194  writeHeader(getTagType(I.TagType) + " " + I.Name, 1, OS);
195  if (I.DefLoc)
196  writeFileDefinition(I.DefLoc.getValue(), OS);
197 
198  if (!I.Description.empty()) {
199  for (const auto &C : I.Description)
200  writeDescription(C, OS);
201  writeNewLine(OS);
202  }
203 
204  std::string Parents = genReferenceList(I.Parents);
205  std::string VParents = genReferenceList(I.VirtualParents);
206  if (!Parents.empty() || !VParents.empty()) {
207  if (Parents.empty())
208  writeLine("Inherits from " + VParents, OS);
209  else if (VParents.empty())
210  writeLine("Inherits from " + Parents, OS);
211  else
212  writeLine("Inherits from " + Parents + ", " + VParents, OS);
213  writeNewLine(OS);
214  }
215 
216  if (!I.Members.empty()) {
217  writeHeader("Members", 2, OS);
218  for (const auto &Member : I.Members) {
219  std::string Access = getAccess(Member.Access);
220  if (Access != "")
221  writeLine(Access + " " + Member.Type.Name + " " + Member.Name, OS);
222  else
223  writeLine(Member.Type.Name + " " + Member.Name, OS);
224  }
225  writeNewLine(OS);
226  }
227 
228  if (!I.ChildRecords.empty()) {
229  writeHeader("Records", 2, OS);
230  for (const auto &R : I.ChildRecords)
231  writeLine(R.Name, OS);
232  writeNewLine(OS);
233  }
234  if (!I.ChildFunctions.empty()) {
235  writeHeader("Functions", 2, OS);
236  for (const auto &F : I.ChildFunctions)
237  genMarkdown(F, OS);
238  writeNewLine(OS);
239  }
240  if (!I.ChildEnums.empty()) {
241  writeHeader("Enums", 2, OS);
242  for (const auto &E : I.ChildEnums)
243  genMarkdown(E, OS);
244  writeNewLine(OS);
245  }
246 }
247 
248 /// Generator for Markdown documentation.
249 class MDGenerator : public Generator {
250 public:
251  static const char *Format;
252 
253  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
254  const ClangDocContext &CDCtx) override;
255 };
256 
257 const char *MDGenerator::Format = "md";
258 
259 llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
260  const ClangDocContext &CDCtx) {
261  switch (I->IT) {
262  case InfoType::IT_namespace:
263  genMarkdown(*static_cast<clang::doc::NamespaceInfo *>(I), OS);
264  break;
265  case InfoType::IT_record:
266  genMarkdown(*static_cast<clang::doc::RecordInfo *>(I), OS);
267  break;
268  case InfoType::IT_enum:
269  genMarkdown(*static_cast<clang::doc::EnumInfo *>(I), OS);
270  break;
271  case InfoType::IT_function:
272  genMarkdown(*static_cast<clang::doc::FunctionInfo *>(I), OS);
273  break;
274  case InfoType::IT_default:
275  return createStringError(llvm::inconvertibleErrorCode(),
276  "unexpected InfoType");
277  }
278  return llvm::Error::success();
279 }
280 
281 static GeneratorRegistry::Add<MDGenerator> MD(MDGenerator::Format,
282  "Generator for MD output.");
283 
284 // This anchor is used to force the linker to link in the generated object file
285 // and thus register the generator.
286 volatile int MDGeneratorAnchorSource = 0;
287 
288 } // namespace doc
289 } // namespace clang
static void writeHeader(const Twine &Text, unsigned int Num, raw_ostream &OS)
Definition: MDGenerator.cpp:49
Some operations such as code completion produce a set of candidates.
static std::string genReferenceList(const llvm::SmallVectorImpl< Reference > &Refs)
Definition: MDGenerator.cpp:32
static void writeDescription(const CommentInfo &I, raw_ostream &OS)
Definition: MDGenerator.cpp:59
SmallString< 16 > Name
llvm::Optional< Location > DefLoc
std::vector< FunctionInfo > ChildFunctions
std::vector< FunctionInfo > ChildFunctions
std::vector< EnumInfo > ChildEnums
static void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS)
std::vector< Reference > ChildRecords
llvm::SmallVector< Reference, 4 > VirtualParents
std::string getAccess(AccessSpecifier AS)
Definition: Generators.cpp:30
llvm::SmallVector< FieldTypeInfo, 4 > Params
static std::string genEmphasis(const Twine &Text)
Definition: MDGenerator.cpp:27
llvm::SmallVector< SmallString< 16 >, 4 > Members
llvm::SmallVector< SmallString< 16 >, 4 > AttrValues
std::vector< CommentInfo > Description
std::string getTagType(TagTypeKind AS)
Definition: Generators.cpp:44
SmallString< 16 > Name
A base struct for Infos.
static void writeNewLine(raw_ostream &OS)
Definition: MDGenerator.cpp:47
llvm::SmallVector< Reference, 4 > Parents
static void writeLine(const Twine &Text, raw_ostream &OS)
Definition: MDGenerator.cpp:43
static const char * Format
static void writeFileDefinition(const Location &L, raw_ostream &OS)
Definition: MDGenerator.cpp:53
volatile int MDGeneratorAnchorSource
SmallString< 16 > ParamName
llvm::SmallVector< SmallString< 16 >, 4 > AttrKeys
SmallString< 16 > Name
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
std::vector< Reference > ChildNamespaces
std::vector< Reference > ChildRecords
Generator for Markdown documentation.
SmallString< 32 > Filename
SmallString< 8 > Direction
const InfoType IT
std::vector< EnumInfo > ChildEnums
const Expr * E
llvm::SmallVector< MemberTypeInfo, 4 > Members
SmallString< 16 > Kind
RefSlab Refs
std::vector< std::unique_ptr< CommentInfo > > Children
SmallString< 64 > Text
static std::string genItalic(const Twine &Text)
Definition: MDGenerator.cpp:23