blob: f8e89f2877304121982b9002032a53b42efbafc8 [file] [log] [blame]
Dmitri Gribenkoae99b752012-07-20 21:34:34 +00001//===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===//
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// This file defines all libclang APIs related to walking comment AST.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang-c/Index.h"
15#include "CXString.h"
16#include "CXComment.h"
17
18#include "clang/AST/CommentVisitor.h"
19
20#include "llvm/Support/ErrorHandling.h"
Dmitri Gribenko3e63d332012-07-21 01:47:43 +000021#include "llvm/Support/raw_ostream.h"
Dmitri Gribenkoae99b752012-07-20 21:34:34 +000022
Dmitri Gribenko221a6d72012-07-30 17:49:32 +000023#include <climits>
24
Dmitri Gribenkoae99b752012-07-20 21:34:34 +000025using namespace clang;
26using namespace clang::cxstring;
27using namespace clang::comments;
28using namespace clang::cxcomment;
29
30extern "C" {
31
32enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
33 const Comment *C = getASTNode(CXC);
34 if (!C)
35 return CXComment_Null;
36
37 switch (C->getCommentKind()) {
38 case Comment::NoCommentKind:
39 return CXComment_Null;
40
41 case Comment::TextCommentKind:
42 return CXComment_Text;
43
44 case Comment::InlineCommandCommentKind:
45 return CXComment_InlineCommand;
46
47 case Comment::HTMLStartTagCommentKind:
48 return CXComment_HTMLStartTag;
49
50 case Comment::HTMLEndTagCommentKind:
51 return CXComment_HTMLEndTag;
52
53 case Comment::ParagraphCommentKind:
54 return CXComment_Paragraph;
55
56 case Comment::BlockCommandCommentKind:
57 return CXComment_BlockCommand;
58
59 case Comment::ParamCommandCommentKind:
60 return CXComment_ParamCommand;
61
62 case Comment::VerbatimBlockCommentKind:
63 return CXComment_VerbatimBlockCommand;
64
65 case Comment::VerbatimBlockLineCommentKind:
66 return CXComment_VerbatimBlockLine;
67
68 case Comment::VerbatimLineCommentKind:
69 return CXComment_VerbatimLine;
70
71 case Comment::FullCommentKind:
72 return CXComment_FullComment;
73 }
74 llvm_unreachable("unknown CommentKind");
75}
76
77unsigned clang_Comment_getNumChildren(CXComment CXC) {
78 const Comment *C = getASTNode(CXC);
79 if (!C)
80 return 0;
81
82 return C->child_count();
83}
84
85CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
86 const Comment *C = getASTNode(CXC);
87 if (!C || ChildIdx >= C->child_count())
88 return createCXComment(NULL);
89
90 return createCXComment(*(C->child_begin() + ChildIdx));
91}
92
93unsigned clang_Comment_isWhitespace(CXComment CXC) {
94 const Comment *C = getASTNode(CXC);
95 if (!C)
96 return false;
97
98 if (const TextComment *TC = dyn_cast<TextComment>(C))
99 return TC->isWhitespace();
100
101 if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
102 return PC->isWhitespace();
103
104 return false;
105}
106
107unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
108 const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
109 if (!ICC)
110 return false;
111
112 return ICC->hasTrailingNewline();
113}
114
115CXString clang_TextComment_getText(CXComment CXC) {
116 const TextComment *TC = getASTNodeAs<TextComment>(CXC);
117 if (!TC)
118 return createCXString((const char *) 0);
119
120 return createCXString(TC->getText(), /*DupString=*/ false);
121}
122
123CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
124 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
125 if (!ICC)
126 return createCXString((const char *) 0);
127
128 return createCXString(ICC->getCommandName(), /*DupString=*/ false);
129}
130
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000131enum CXCommentInlineCommandRenderKind
132clang_InlineCommandComment_getRenderKind(CXComment CXC) {
133 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
134 if (!ICC)
135 return CXCommentInlineCommandRenderKind_Normal;
136
137 switch (ICC->getRenderKind()) {
138 case InlineCommandComment::RenderNormal:
139 return CXCommentInlineCommandRenderKind_Normal;
140
141 case InlineCommandComment::RenderBold:
142 return CXCommentInlineCommandRenderKind_Bold;
143
144 case InlineCommandComment::RenderMonospaced:
145 return CXCommentInlineCommandRenderKind_Monospaced;
146
147 case InlineCommandComment::RenderEmphasized:
148 return CXCommentInlineCommandRenderKind_Emphasized;
149 }
150 llvm_unreachable("unknown InlineCommandComment::RenderKind");
151}
152
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000153unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
154 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
155 if (!ICC)
156 return 0;
157
158 return ICC->getNumArgs();
159}
160
161CXString clang_InlineCommandComment_getArgText(CXComment CXC,
162 unsigned ArgIdx) {
163 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
164 if (!ICC || ArgIdx >= ICC->getNumArgs())
165 return createCXString((const char *) 0);
166
167 return createCXString(ICC->getArgText(ArgIdx), /*DupString=*/ false);
168}
169
170CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
171 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
172 if (!HTC)
173 return createCXString((const char *) 0);
174
175 return createCXString(HTC->getTagName(), /*DupString=*/ false);
176}
177
178unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
179 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
180 if (!HST)
181 return false;
182
183 return HST->isSelfClosing();
184}
185
186unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
187 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
188 if (!HST)
189 return 0;
190
191 return HST->getNumAttrs();
192}
193
194CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
195 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
196 if (!HST || AttrIdx >= HST->getNumAttrs())
197 return createCXString((const char *) 0);
198
199 return createCXString(HST->getAttr(AttrIdx).Name, /*DupString=*/ false);
200}
201
202CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
203 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
204 if (!HST || AttrIdx >= HST->getNumAttrs())
205 return createCXString((const char *) 0);
206
207 return createCXString(HST->getAttr(AttrIdx).Value, /*DupString=*/ false);
208}
209
210CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
211 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
212 if (!BCC)
213 return createCXString((const char *) 0);
214
215 return createCXString(BCC->getCommandName(), /*DupString=*/ false);
216}
217
218unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
219 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
220 if (!BCC)
221 return 0;
222
223 return BCC->getNumArgs();
224}
225
226CXString clang_BlockCommandComment_getArgText(CXComment CXC,
227 unsigned ArgIdx) {
228 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
229 if (!BCC || ArgIdx >= BCC->getNumArgs())
230 return createCXString((const char *) 0);
231
232 return createCXString(BCC->getArgText(ArgIdx), /*DupString=*/ false);
233}
234
235CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
236 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
237 if (!BCC)
238 return createCXComment(NULL);
239
240 return createCXComment(BCC->getParagraph());
241}
242
243CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
244 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
Dmitri Gribenko1f8c5292012-07-23 19:41:49 +0000245 if (!PCC || !PCC->hasParamName())
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000246 return createCXString((const char *) 0);
247
248 return createCXString(PCC->getParamName(), /*DupString=*/ false);
249}
250
251unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
252 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
253 if (!PCC)
254 return false;
255
256 return PCC->isParamIndexValid();
257}
258
259unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
260 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
Dmitri Gribenkob7403162012-07-30 17:38:19 +0000261 if (!PCC || !PCC->isParamIndexValid())
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000262 return ParamCommandComment::InvalidParamIndex;
263
264 return PCC->getParamIndex();
265}
266
267unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
268 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
269 if (!PCC)
270 return false;
271
272 return PCC->isDirectionExplicit();
273}
274
275enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
276 CXComment CXC) {
277 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
278 if (!PCC)
279 return CXCommentParamPassDirection_In;
280
281 switch (PCC->getDirection()) {
282 case ParamCommandComment::In:
283 return CXCommentParamPassDirection_In;
284
285 case ParamCommandComment::Out:
286 return CXCommentParamPassDirection_Out;
287
288 case ParamCommandComment::InOut:
289 return CXCommentParamPassDirection_InOut;
290 }
291 llvm_unreachable("unknown ParamCommandComment::PassDirection");
292}
293
294CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
295 const VerbatimBlockLineComment *VBL =
296 getASTNodeAs<VerbatimBlockLineComment>(CXC);
297 if (!VBL)
298 return createCXString((const char *) 0);
299
300 return createCXString(VBL->getText(), /*DupString=*/ false);
301}
302
303CXString clang_VerbatimLineComment_getText(CXComment CXC) {
304 const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
305 if (!VLC)
306 return createCXString((const char *) 0);
307
308 return createCXString(VLC->getText(), /*DupString=*/ false);
309}
310
311} // end extern "C"
312
313//===----------------------------------------------------------------------===//
314// Helpers for converting comment AST to HTML.
315//===----------------------------------------------------------------------===//
316
317namespace {
318
Dmitri Gribenkoe5db09c2012-07-30 19:47:34 +0000319/// This comparison will sort parameters with valid index by index and
320/// invalid (unresolved) parameters last.
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000321class ParamCommandCommentCompareIndex {
322public:
323 bool operator()(const ParamCommandComment *LHS,
324 const ParamCommandComment *RHS) const {
Dmitri Gribenkob7403162012-07-30 17:38:19 +0000325 unsigned LHSIndex = UINT_MAX;
326 unsigned RHSIndex = UINT_MAX;
327 if (LHS->isParamIndexValid())
328 LHSIndex = LHS->getParamIndex();
329 if (RHS->isParamIndexValid())
330 RHSIndex = RHS->getParamIndex();
331
332 return LHSIndex < RHSIndex;
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000333 }
334};
335
336class CommentASTToHTMLConverter :
337 public ConstCommentVisitor<CommentASTToHTMLConverter> {
338public:
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000339 /// \param Str accumulator for HTML.
340 CommentASTToHTMLConverter(SmallVectorImpl<char> &Str) : Result(Str) { }
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000341
342 // Inline content.
343 void visitTextComment(const TextComment *C);
344 void visitInlineCommandComment(const InlineCommandComment *C);
345 void visitHTMLStartTagComment(const HTMLStartTagComment *C);
346 void visitHTMLEndTagComment(const HTMLEndTagComment *C);
347
348 // Block content.
349 void visitParagraphComment(const ParagraphComment *C);
350 void visitBlockCommandComment(const BlockCommandComment *C);
351 void visitParamCommandComment(const ParamCommandComment *C);
352 void visitVerbatimBlockComment(const VerbatimBlockComment *C);
353 void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
354 void visitVerbatimLineComment(const VerbatimLineComment *C);
355
356 void visitFullComment(const FullComment *C);
357
358 // Helpers.
359
360 /// Convert a paragraph that is not a block by itself (an argument to some
361 /// command).
362 void visitNonStandaloneParagraphComment(const ParagraphComment *C);
363
364 void appendToResultWithHTMLEscaping(StringRef S);
365
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000366private:
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000367 /// Output stream for HTML.
368 llvm::raw_svector_ostream Result;
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000369};
370} // end unnamed namespace
371
372void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
373 appendToResultWithHTMLEscaping(C->getText());
374}
375
376void CommentASTToHTMLConverter::visitInlineCommandComment(
377 const InlineCommandComment *C) {
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000378 // Nothing to render if no arguments supplied.
379 if (C->getNumArgs() == 0)
380 return;
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000381
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000382 // Nothing to render if argument is empty.
383 StringRef Arg0 = C->getArgText(0);
384 if (Arg0.empty())
385 return;
386
387 switch (C->getRenderKind()) {
388 case InlineCommandComment::RenderNormal:
389 for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
390 Result << C->getArgText(i) << " ";
391 return;
392
393 case InlineCommandComment::RenderBold:
394 assert(C->getNumArgs() == 1);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000395 Result << "<b>" << Arg0 << "</b>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000396 return;
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000397 case InlineCommandComment::RenderMonospaced:
398 assert(C->getNumArgs() == 1);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000399 Result << "<tt>" << Arg0 << "</tt>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000400 return;
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000401 case InlineCommandComment::RenderEmphasized:
402 assert(C->getNumArgs() == 1);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000403 Result << "<em>" << Arg0 << "</em>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000404 return;
405 }
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000406}
407
408void CommentASTToHTMLConverter::visitHTMLStartTagComment(
409 const HTMLStartTagComment *C) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000410 Result << "<" << C->getTagName();
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000411
412 if (C->getNumAttrs() != 0) {
413 for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000414 Result << " ";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000415 const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000416 Result << Attr.Name;
417 if (!Attr.Value.empty())
418 Result << "=\"" << Attr.Value << "\"";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000419 }
420 }
421
422 if (!C->isSelfClosing())
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000423 Result << ">";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000424 else
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000425 Result << "/>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000426}
427
428void CommentASTToHTMLConverter::visitHTMLEndTagComment(
429 const HTMLEndTagComment *C) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000430 Result << "</" << C->getTagName() << ">";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000431}
432
433void CommentASTToHTMLConverter::visitParagraphComment(
434 const ParagraphComment *C) {
435 if (C->isWhitespace())
436 return;
437
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000438 Result << "<p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000439 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
440 I != E; ++I) {
441 visit(*I);
442 }
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000443 Result << "</p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000444}
445
446void CommentASTToHTMLConverter::visitBlockCommandComment(
447 const BlockCommandComment *C) {
448 StringRef CommandName = C->getCommandName();
449 if (CommandName == "brief" || CommandName == "short") {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000450 Result << "<p class=\"para-brief\">";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000451 visitNonStandaloneParagraphComment(C->getParagraph());
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000452 Result << "</p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000453 return;
454 }
Dmitri Gribenko2c6b00e2012-07-25 17:14:58 +0000455 if (CommandName == "returns" || CommandName == "return" ||
456 CommandName == "result") {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000457 Result << "<p class=\"para-returns\">"
458 "<span class=\"word-returns\">Returns</span> ";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000459 visitNonStandaloneParagraphComment(C->getParagraph());
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000460 Result << "</p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000461 return;
462 }
463 // We don't know anything about this command. Just render the paragraph.
464 visit(C->getParagraph());
465}
466
467void CommentASTToHTMLConverter::visitParamCommandComment(
468 const ParamCommandComment *C) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000469 if (C->isParamIndexValid()) {
470 Result << "<dt class=\"param-name-index-"
471 << C->getParamIndex()
472 << "\">";
473 } else
474 Result << "<dt class=\"param-name-index-invalid\">";
475
476 Result << C->getParamName() << "</dt>";
477
478 if (C->isParamIndexValid()) {
479 Result << "<dd class=\"param-descr-index-"
480 << C->getParamIndex()
481 << "\">";
482 } else
483 Result << "<dd class=\"param-descr-index-invalid\">";
484
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000485 visitNonStandaloneParagraphComment(C->getParagraph());
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000486 Result << "</dd>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000487}
488
489void CommentASTToHTMLConverter::visitVerbatimBlockComment(
490 const VerbatimBlockComment *C) {
491 unsigned NumLines = C->getNumLines();
492 if (NumLines == 0)
493 return;
494
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000495 Result << "<pre>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000496 for (unsigned i = 0; i != NumLines; ++i) {
497 appendToResultWithHTMLEscaping(C->getText(i));
498 if (i + 1 != NumLines)
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000499 Result << '\n';
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000500 }
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000501 Result << "</pre>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000502}
503
504void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
505 const VerbatimBlockLineComment *C) {
506 llvm_unreachable("should not see this AST node");
507}
508
509void CommentASTToHTMLConverter::visitVerbatimLineComment(
510 const VerbatimLineComment *C) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000511 Result << "<pre>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000512 appendToResultWithHTMLEscaping(C->getText());
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000513 Result << "</pre>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000514}
515
516void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
517 const BlockContentComment *Brief = NULL;
518 const ParagraphComment *FirstParagraph = NULL;
519 const BlockCommandComment *Returns = NULL;
520 SmallVector<const ParamCommandComment *, 8> Params;
521 SmallVector<const BlockContentComment *, 8> MiscBlocks;
522
523 // Extract various blocks into separate variables and vectors above.
524 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
525 I != E; ++I) {
526 const Comment *Child = *I;
527 if (!Child)
528 continue;
529 switch (Child->getCommentKind()) {
530 case Comment::NoCommentKind:
531 continue;
532
533 case Comment::ParagraphCommentKind: {
534 const ParagraphComment *PC = cast<ParagraphComment>(Child);
535 if (PC->isWhitespace())
536 break;
537 if (!FirstParagraph)
538 FirstParagraph = PC;
539
540 MiscBlocks.push_back(PC);
541 break;
542 }
543
544 case Comment::BlockCommandCommentKind: {
545 const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
546 StringRef CommandName = BCC->getCommandName();
547 if (!Brief && (CommandName == "brief" || CommandName == "short")) {
548 Brief = BCC;
549 break;
550 }
551 if (!Returns && (CommandName == "returns" || CommandName == "return")) {
552 Returns = BCC;
553 break;
554 }
555 MiscBlocks.push_back(BCC);
556 break;
557 }
558
559 case Comment::ParamCommandCommentKind: {
560 const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
561 if (!PCC->hasParamName())
562 break;
563
564 if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
565 break;
566
567 Params.push_back(PCC);
568 break;
569 }
570
571 case Comment::VerbatimBlockCommentKind:
572 case Comment::VerbatimLineCommentKind:
573 MiscBlocks.push_back(cast<BlockCommandComment>(Child));
574 break;
575
576 case Comment::TextCommentKind:
577 case Comment::InlineCommandCommentKind:
578 case Comment::HTMLStartTagCommentKind:
579 case Comment::HTMLEndTagCommentKind:
580 case Comment::VerbatimBlockLineCommentKind:
581 case Comment::FullCommentKind:
582 llvm_unreachable("AST node of this kind can't be a child of "
583 "a FullComment");
584 }
585 }
586
587 // Sort params in order they are declared in the function prototype.
588 // Unresolved parameters are put at the end of the list in the same order
589 // they were seen in the comment.
590 std::stable_sort(Params.begin(), Params.end(),
591 ParamCommandCommentCompareIndex());
592
593 bool FirstParagraphIsBrief = false;
594 if (Brief)
595 visit(Brief);
596 else if (FirstParagraph) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000597 Result << "<p class=\"para-brief\">";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000598 visitNonStandaloneParagraphComment(FirstParagraph);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000599 Result << "</p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000600 FirstParagraphIsBrief = true;
601 }
602
603 for (unsigned i = 0, e = MiscBlocks.size(); i != e; ++i) {
604 const Comment *C = MiscBlocks[i];
605 if (FirstParagraphIsBrief && C == FirstParagraph)
606 continue;
607 visit(C);
608 }
609
610 if (Params.size() != 0) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000611 Result << "<dl>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000612 for (unsigned i = 0, e = Params.size(); i != e; ++i)
613 visit(Params[i]);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000614 Result << "</dl>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000615 }
616
617 if (Returns)
618 visit(Returns);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000619
620 Result.flush();
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000621}
622
623void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
624 const ParagraphComment *C) {
625 if (!C)
626 return;
627
628 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
629 I != E; ++I) {
630 visit(*I);
631 }
632}
633
634void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000635 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
636 const char C = *I;
637 switch (C) {
638 case '&':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000639 Result << "&amp;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000640 break;
641 case '<':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000642 Result << "&lt;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000643 break;
644 case '>':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000645 Result << "&gt;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000646 break;
647 case '"':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000648 Result << "&quot;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000649 break;
650 case '\'':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000651 Result << "&#39;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000652 break;
653 case '/':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000654 Result << "&#47;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000655 break;
656 default:
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000657 Result << C;
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000658 break;
659 }
660 }
661}
662
663extern "C" {
664
665CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
666 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
667 if (!HTC)
668 return createCXString((const char *) 0);
669
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000670 SmallString<128> HTML;
671 CommentASTToHTMLConverter Converter(HTML);
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000672 Converter.visit(HTC);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000673 return createCXString(HTML.str(), /* DupString = */ true);
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000674}
675
676CXString clang_FullComment_getAsHTML(CXComment CXC) {
677 const FullComment *FC = getASTNodeAs<FullComment>(CXC);
678 if (!FC)
679 return createCXString((const char *) 0);
680
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000681 SmallString<1024> HTML;
682 CommentASTToHTMLConverter Converter(HTML);
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000683 Converter.visit(FC);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000684 return createCXString(HTML.str(), /* DupString = */ true);
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000685}
686
687} // end extern "C"
688