clang-tools  8.0.0
MDGenerator.cpp
Go to the documentation of this file.
1 //===-- MDGenerator.cpp - Markdown Generator --------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "Generators.h"
11 #include "Representation.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/Path.h"
15 #include <string>
16 
17 using namespace llvm;
18 
19 namespace clang {
20 namespace doc {
21 
22 // Enum conversion
23 
24 std::string getAccess(AccessSpecifier AS) {
25  switch (AS) {
26  case AccessSpecifier::AS_public:
27  return "public";
28  case AccessSpecifier::AS_protected:
29  return "protected";
30  case AccessSpecifier::AS_private:
31  return "private";
32  case AccessSpecifier::AS_none:
33  return {};
34  }
35  llvm_unreachable("Unknown AccessSpecifier");
36 }
37 
38 std::string getTagType(TagTypeKind AS) {
39  switch (AS) {
40  case TagTypeKind::TTK_Class:
41  return "class";
42  case TagTypeKind::TTK_Union:
43  return "union";
44  case TagTypeKind::TTK_Interface:
45  return "interface";
46  case TagTypeKind::TTK_Struct:
47  return "struct";
48  case TagTypeKind::TTK_Enum:
49  return "enum";
50  }
51  llvm_unreachable("Unknown TagTypeKind");
52 }
53 
54 // Markdown generation
55 
56 std::string genItalic(const Twine &Text) { return "*" + Text.str() + "*"; }
57 
58 std::string genEmphasis(const Twine &Text) { return "**" + Text.str() + "**"; }
59 
60 std::string genLink(const Twine &Text, const Twine &Link) {
61  return "[" + Text.str() + "](" + Link.str() + ")";
62 }
63 
64 std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
65  std::string Buffer;
66  llvm::raw_string_ostream Stream(Buffer);
67  bool First = true;
68  for (const auto &R : Refs) {
69  if (!First)
70  Stream << ", ";
71  Stream << R.Name;
72  First = false;
73  }
74  return Stream.str();
75 }
76 
77 void writeLine(const Twine &Text, raw_ostream &OS) { OS << Text << "\n\n"; }
78 
79 void writeNewLine(raw_ostream &OS) { OS << "\n\n"; }
80 
81 void writeHeader(const Twine &Text, unsigned int Num, raw_ostream &OS) {
82  OS << std::string(Num, '#') + " " + Text << "\n\n";
83 }
84 
85 void writeFileDefinition(const Location &L, raw_ostream &OS) {
86  OS << genItalic("Defined at line " + std::to_string(L.LineNumber) + " of " +
87  L.Filename)
88  << "\n\n";
89 }
90 
91 void writeDescription(const CommentInfo &I, raw_ostream &OS) {
92  if (I.Kind == "FullComment") {
93  for (const auto &Child : I.Children)
94  writeDescription(*Child, OS);
95  } else if (I.Kind == "ParagraphComment") {
96  for (const auto &Child : I.Children)
97  writeDescription(*Child, OS);
98  writeNewLine(OS);
99  } else if (I.Kind == "BlockCommandComment") {
100  OS << genEmphasis(I.Name);
101  for (const auto &Child : I.Children)
102  writeDescription(*Child, OS);
103  } else if (I.Kind == "InlineCommandComment") {
104  OS << genEmphasis(I.Name) << " " << I.Text;
105  } else if (I.Kind == "ParamCommandComment") {
106  std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
107  OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
108  } else if (I.Kind == "TParamCommandComment") {
109  std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
110  OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
111  } else if (I.Kind == "VerbatimBlockComment") {
112  for (const auto &Child : I.Children)
113  writeDescription(*Child, OS);
114  } else if (I.Kind == "VerbatimBlockLineComment") {
115  OS << I.Text;
116  writeNewLine(OS);
117  } else if (I.Kind == "VerbatimLineComment") {
118  OS << I.Text;
119  writeNewLine(OS);
120  } else if (I.Kind == "HTMLStartTagComment") {
121  if (I.AttrKeys.size() != I.AttrValues.size())
122  return;
123  std::string Buffer;
124  llvm::raw_string_ostream Attrs(Buffer);
125  for (unsigned Idx = 0; Idx < I.AttrKeys.size(); ++Idx)
126  Attrs << " \"" << I.AttrKeys[Idx] << "=" << I.AttrValues[Idx] << "\"";
127 
128  std::string CloseTag = I.SelfClosing ? "/>" : ">";
129  writeLine("<" + I.Name + Attrs.str() + CloseTag, OS);
130  } else if (I.Kind == "HTMLEndTagComment") {
131  writeLine("</" + I.Name + ">", OS);
132  } else if (I.Kind == "TextComment") {
133  OS << I.Text;
134  } else {
135  OS << "Unknown comment kind: " << I.Kind << ".\n\n";
136  }
137 }
138 
139 void genMarkdown(const EnumInfo &I, llvm::raw_ostream &OS) {
140  if (I.Scoped)
141  writeLine("| enum class " + I.Name + " |", OS);
142  else
143  writeLine("| enum " + I.Name + " |", OS);
144  writeLine("--", OS);
145 
146  std::string Buffer;
147  llvm::raw_string_ostream Members(Buffer);
148  if (!I.Members.empty())
149  for (const auto &N : I.Members)
150  Members << "| " << N << " |\n";
151  writeLine(Members.str(), OS);
152  if (I.DefLoc)
153  writeFileDefinition(I.DefLoc.getValue(), OS);
154 
155  for (const auto &C : I.Description)
156  writeDescription(C, OS);
157 }
158 
159 void genMarkdown(const FunctionInfo &I, llvm::raw_ostream &OS) {
160  std::string Buffer;
161  llvm::raw_string_ostream Stream(Buffer);
162  bool First = true;
163  for (const auto &N : I.Params) {
164  if (!First)
165  Stream << ", ";
166  Stream << N.Type.Name + " " + N.Name;
167  First = false;
168  }
169  writeHeader(I.Name, 3, OS);
170  std::string Access = getAccess(I.Access);
171  if (Access != "")
172  writeLine(genItalic(Access + " " + I.ReturnType.Type.Name + " " + I.Name +
173  "(" + Stream.str() + ")"),
174  OS);
175  else
176  writeLine(genItalic(I.ReturnType.Type.Name + " " + I.Name + "(" +
177  Stream.str() + ")"),
178  OS);
179  if (I.DefLoc)
180  writeFileDefinition(I.DefLoc.getValue(), OS);
181 
182  for (const auto &C : I.Description)
183  writeDescription(C, OS);
184 }
185 
186 void genMarkdown(const NamespaceInfo &I, llvm::raw_ostream &OS) {
187  if (I.Name == "")
188  writeHeader("Global Namespace", 1, OS);
189  else
190  writeHeader("namespace " + I.Name, 1, OS);
191  writeNewLine(OS);
192 
193  if (!I.Description.empty()) {
194  for (const auto &C : I.Description)
195  writeDescription(C, OS);
196  writeNewLine(OS);
197  }
198 
199  if (!I.ChildNamespaces.empty()) {
200  writeHeader("Namespaces", 2, OS);
201  for (const auto &R : I.ChildNamespaces)
202  writeLine(R.Name, OS);
203  writeNewLine(OS);
204  }
205  if (!I.ChildRecords.empty()) {
206  writeHeader("Records", 2, OS);
207  for (const auto &R : I.ChildRecords)
208  writeLine(R.Name, OS);
209  writeNewLine(OS);
210  }
211  if (!I.ChildFunctions.empty()) {
212  writeHeader("Functions", 2, OS);
213  for (const auto &F : I.ChildFunctions)
214  genMarkdown(F, OS);
215  writeNewLine(OS);
216  }
217  if (!I.ChildEnums.empty()) {
218  writeHeader("Enums", 2, OS);
219  for (const auto &E : I.ChildEnums)
220  genMarkdown(E, OS);
221  writeNewLine(OS);
222  }
223 }
224 
225 void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS) {
226  writeHeader(getTagType(I.TagType) + " " + I.Name, 1, OS);
227  if (I.DefLoc)
228  writeFileDefinition(I.DefLoc.getValue(), OS);
229 
230  if (!I.Description.empty()) {
231  for (const auto &C : I.Description)
232  writeDescription(C, OS);
233  writeNewLine(OS);
234  }
235 
236  std::string Parents = genReferenceList(I.Parents);
237  std::string VParents = genReferenceList(I.VirtualParents);
238  if (!Parents.empty() || !VParents.empty()) {
239  if (Parents.empty())
240  writeLine("Inherits from " + VParents, OS);
241  else if (VParents.empty())
242  writeLine("Inherits from " + Parents, OS);
243  else
244  writeLine("Inherits from " + Parents + ", " + VParents, OS);
245  writeNewLine(OS);
246  }
247 
248  if (!I.Members.empty()) {
249  writeHeader("Members", 2, OS);
250  for (const auto Member : I.Members) {
251  std::string Access = getAccess(Member.Access);
252  if (Access != "")
253  writeLine(Access + " " + Member.Type.Name + " " + Member.Name, OS);
254  else
255  writeLine(Member.Type.Name + " " + Member.Name, OS);
256  }
257  writeNewLine(OS);
258  }
259 
260  if (!I.ChildRecords.empty()) {
261  writeHeader("Records", 2, OS);
262  for (const auto &R : I.ChildRecords)
263  writeLine(R.Name, OS);
264  writeNewLine(OS);
265  }
266  if (!I.ChildFunctions.empty()) {
267  writeHeader("Functions", 2, OS);
268  for (const auto &F : I.ChildFunctions)
269  genMarkdown(F, OS);
270  writeNewLine(OS);
271  }
272  if (!I.ChildEnums.empty()) {
273  writeHeader("Enums", 2, OS);
274  for (const auto &E : I.ChildEnums)
275  genMarkdown(E, OS);
276  writeNewLine(OS);
277  }
278 }
279 
280 /// Generator for Markdown documentation.
281 class MDGenerator : public Generator {
282 public:
283  static const char *Format;
284 
285  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
286 };
287 
288 const char *MDGenerator::Format = "md";
289 
290 llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
291  switch (I->IT) {
292  case InfoType::IT_namespace:
293  genMarkdown(*static_cast<clang::doc::NamespaceInfo *>(I), OS);
294  break;
295  case InfoType::IT_record:
296  genMarkdown(*static_cast<clang::doc::RecordInfo *>(I), OS);
297  break;
298  case InfoType::IT_enum:
299  genMarkdown(*static_cast<clang::doc::EnumInfo *>(I), OS);
300  break;
301  case InfoType::IT_function:
302  genMarkdown(*static_cast<clang::doc::FunctionInfo *>(I), OS);
303  break;
304  case InfoType::IT_default:
305  return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
306  llvm::inconvertibleErrorCode());
307  }
308  return llvm::Error::success();
309 }
310 
311 static GeneratorRegistry::Add<MDGenerator> MD(MDGenerator::Format,
312  "Generator for MD output.");
313 
314 // This anchor is used to force the linker to link in the generated object file
315 // and thus register the generator.
316 volatile int MDGeneratorAnchorSource = 0;
317 
318 } // namespace doc
319 } // namespace clang
void writeFileDefinition(const Location &L, raw_ostream &OS)
Definition: MDGenerator.cpp:85
Some operations such as code completion produce a set of candidates.
void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS)
void writeHeader(const Twine &Text, unsigned int Num, raw_ostream &OS)
Definition: MDGenerator.cpp:81
SmallString< 16 > Name
llvm::Optional< Location > DefLoc
void writeNewLine(raw_ostream &OS)
Definition: MDGenerator.cpp:79
std::vector< FunctionInfo > ChildFunctions
std::vector< FunctionInfo > ChildFunctions
std::vector< EnumInfo > ChildEnums
std::vector< Reference > ChildRecords
llvm::SmallVector< Reference, 4 > VirtualParents
std::string getAccess(AccessSpecifier AS)
Definition: MDGenerator.cpp:24
llvm::SmallVector< FieldTypeInfo, 4 > Params
llvm::SmallVector< SmallString< 16 >, 4 > Members
llvm::SmallVector< SmallString< 16 >, 4 > AttrValues
std::vector< CommentInfo > Description
std::string getTagType(TagTypeKind AS)
Definition: MDGenerator.cpp:38
SmallString< 16 > Name
void writeLine(const Twine &Text, raw_ostream &OS)
Definition: MDGenerator.cpp:77
A base struct for Infos.
llvm::SmallVector< Reference, 4 > Parents
static const char * Format
volatile int MDGeneratorAnchorSource
SmallString< 16 > ParamName
void writeDescription(const CommentInfo &I, raw_ostream &OS)
Definition: MDGenerator.cpp:91
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::string genEmphasis(const Twine &Text)
Definition: MDGenerator.cpp:58
std::vector< Reference > ChildRecords
Generator for Markdown documentation.
SmallString< 32 > Filename
SmallString< 8 > Direction
std::string genLink(const Twine &Text, const Twine &Link)
Definition: MDGenerator.cpp:60
const InfoType IT
std::vector< EnumInfo > ChildEnums
llvm::SmallVector< MemberTypeInfo, 4 > Members
SmallString< 16 > Kind
std::string genReferenceList(const llvm::SmallVectorImpl< Reference > &Refs)
Definition: MDGenerator.cpp:64
std::vector< std::unique_ptr< CommentInfo > > Children
SmallString< 64 > Text
std::string genItalic(const Twine &Text)
Definition: MDGenerator.cpp:56