blob: b0ed9bcc00eaac64794cd15ef192e226b533b3b5 [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
23using namespace clang;
24using namespace clang::cxstring;
25using namespace clang::comments;
26using namespace clang::cxcomment;
27
28extern "C" {
29
30enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
31 const Comment *C = getASTNode(CXC);
32 if (!C)
33 return CXComment_Null;
34
35 switch (C->getCommentKind()) {
36 case Comment::NoCommentKind:
37 return CXComment_Null;
38
39 case Comment::TextCommentKind:
40 return CXComment_Text;
41
42 case Comment::InlineCommandCommentKind:
43 return CXComment_InlineCommand;
44
45 case Comment::HTMLStartTagCommentKind:
46 return CXComment_HTMLStartTag;
47
48 case Comment::HTMLEndTagCommentKind:
49 return CXComment_HTMLEndTag;
50
51 case Comment::ParagraphCommentKind:
52 return CXComment_Paragraph;
53
54 case Comment::BlockCommandCommentKind:
55 return CXComment_BlockCommand;
56
57 case Comment::ParamCommandCommentKind:
58 return CXComment_ParamCommand;
59
60 case Comment::VerbatimBlockCommentKind:
61 return CXComment_VerbatimBlockCommand;
62
63 case Comment::VerbatimBlockLineCommentKind:
64 return CXComment_VerbatimBlockLine;
65
66 case Comment::VerbatimLineCommentKind:
67 return CXComment_VerbatimLine;
68
69 case Comment::FullCommentKind:
70 return CXComment_FullComment;
71 }
72 llvm_unreachable("unknown CommentKind");
73}
74
75unsigned clang_Comment_getNumChildren(CXComment CXC) {
76 const Comment *C = getASTNode(CXC);
77 if (!C)
78 return 0;
79
80 return C->child_count();
81}
82
83CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
84 const Comment *C = getASTNode(CXC);
85 if (!C || ChildIdx >= C->child_count())
86 return createCXComment(NULL);
87
88 return createCXComment(*(C->child_begin() + ChildIdx));
89}
90
91unsigned clang_Comment_isWhitespace(CXComment CXC) {
92 const Comment *C = getASTNode(CXC);
93 if (!C)
94 return false;
95
96 if (const TextComment *TC = dyn_cast<TextComment>(C))
97 return TC->isWhitespace();
98
99 if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
100 return PC->isWhitespace();
101
102 return false;
103}
104
105unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
106 const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
107 if (!ICC)
108 return false;
109
110 return ICC->hasTrailingNewline();
111}
112
113CXString clang_TextComment_getText(CXComment CXC) {
114 const TextComment *TC = getASTNodeAs<TextComment>(CXC);
115 if (!TC)
116 return createCXString((const char *) 0);
117
118 return createCXString(TC->getText(), /*DupString=*/ false);
119}
120
121CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
122 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
123 if (!ICC)
124 return createCXString((const char *) 0);
125
126 return createCXString(ICC->getCommandName(), /*DupString=*/ false);
127}
128
129unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
130 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
131 if (!ICC)
132 return 0;
133
134 return ICC->getNumArgs();
135}
136
137CXString clang_InlineCommandComment_getArgText(CXComment CXC,
138 unsigned ArgIdx) {
139 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
140 if (!ICC || ArgIdx >= ICC->getNumArgs())
141 return createCXString((const char *) 0);
142
143 return createCXString(ICC->getArgText(ArgIdx), /*DupString=*/ false);
144}
145
146CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
147 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
148 if (!HTC)
149 return createCXString((const char *) 0);
150
151 return createCXString(HTC->getTagName(), /*DupString=*/ false);
152}
153
154unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
155 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
156 if (!HST)
157 return false;
158
159 return HST->isSelfClosing();
160}
161
162unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
163 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
164 if (!HST)
165 return 0;
166
167 return HST->getNumAttrs();
168}
169
170CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
171 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
172 if (!HST || AttrIdx >= HST->getNumAttrs())
173 return createCXString((const char *) 0);
174
175 return createCXString(HST->getAttr(AttrIdx).Name, /*DupString=*/ false);
176}
177
178CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
179 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
180 if (!HST || AttrIdx >= HST->getNumAttrs())
181 return createCXString((const char *) 0);
182
183 return createCXString(HST->getAttr(AttrIdx).Value, /*DupString=*/ false);
184}
185
186CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
187 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
188 if (!BCC)
189 return createCXString((const char *) 0);
190
191 return createCXString(BCC->getCommandName(), /*DupString=*/ false);
192}
193
194unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
195 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
196 if (!BCC)
197 return 0;
198
199 return BCC->getNumArgs();
200}
201
202CXString clang_BlockCommandComment_getArgText(CXComment CXC,
203 unsigned ArgIdx) {
204 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
205 if (!BCC || ArgIdx >= BCC->getNumArgs())
206 return createCXString((const char *) 0);
207
208 return createCXString(BCC->getArgText(ArgIdx), /*DupString=*/ false);
209}
210
211CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
212 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
213 if (!BCC)
214 return createCXComment(NULL);
215
216 return createCXComment(BCC->getParagraph());
217}
218
219CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
220 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
221 if (!PCC)
222 return createCXString((const char *) 0);
223
224 return createCXString(PCC->getParamName(), /*DupString=*/ false);
225}
226
227unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
228 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
229 if (!PCC)
230 return false;
231
232 return PCC->isParamIndexValid();
233}
234
235unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
236 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
237 if (!PCC)
238 return ParamCommandComment::InvalidParamIndex;
239
240 return PCC->getParamIndex();
241}
242
243unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
244 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
245 if (!PCC)
246 return false;
247
248 return PCC->isDirectionExplicit();
249}
250
251enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
252 CXComment CXC) {
253 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
254 if (!PCC)
255 return CXCommentParamPassDirection_In;
256
257 switch (PCC->getDirection()) {
258 case ParamCommandComment::In:
259 return CXCommentParamPassDirection_In;
260
261 case ParamCommandComment::Out:
262 return CXCommentParamPassDirection_Out;
263
264 case ParamCommandComment::InOut:
265 return CXCommentParamPassDirection_InOut;
266 }
267 llvm_unreachable("unknown ParamCommandComment::PassDirection");
268}
269
270CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
271 const VerbatimBlockLineComment *VBL =
272 getASTNodeAs<VerbatimBlockLineComment>(CXC);
273 if (!VBL)
274 return createCXString((const char *) 0);
275
276 return createCXString(VBL->getText(), /*DupString=*/ false);
277}
278
279CXString clang_VerbatimLineComment_getText(CXComment CXC) {
280 const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
281 if (!VLC)
282 return createCXString((const char *) 0);
283
284 return createCXString(VLC->getText(), /*DupString=*/ false);
285}
286
287} // end extern "C"
288
289//===----------------------------------------------------------------------===//
290// Helpers for converting comment AST to HTML.
291//===----------------------------------------------------------------------===//
292
293namespace {
294
295class ParamCommandCommentCompareIndex {
296public:
297 bool operator()(const ParamCommandComment *LHS,
298 const ParamCommandComment *RHS) const {
299 // To sort invalid (unresolved) parameters last, this comparison relies on
300 // invalid indices to be UINT_MAX.
301 return LHS->getParamIndex() < RHS->getParamIndex();
302 }
303};
304
305class CommentASTToHTMLConverter :
306 public ConstCommentVisitor<CommentASTToHTMLConverter> {
307public:
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000308 /// \param Str accumulator for HTML.
309 CommentASTToHTMLConverter(SmallVectorImpl<char> &Str) : Result(Str) { }
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000310
311 // Inline content.
312 void visitTextComment(const TextComment *C);
313 void visitInlineCommandComment(const InlineCommandComment *C);
314 void visitHTMLStartTagComment(const HTMLStartTagComment *C);
315 void visitHTMLEndTagComment(const HTMLEndTagComment *C);
316
317 // Block content.
318 void visitParagraphComment(const ParagraphComment *C);
319 void visitBlockCommandComment(const BlockCommandComment *C);
320 void visitParamCommandComment(const ParamCommandComment *C);
321 void visitVerbatimBlockComment(const VerbatimBlockComment *C);
322 void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
323 void visitVerbatimLineComment(const VerbatimLineComment *C);
324
325 void visitFullComment(const FullComment *C);
326
327 // Helpers.
328
329 /// Convert a paragraph that is not a block by itself (an argument to some
330 /// command).
331 void visitNonStandaloneParagraphComment(const ParagraphComment *C);
332
333 void appendToResultWithHTMLEscaping(StringRef S);
334
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000335private:
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000336 /// Output stream for HTML.
337 llvm::raw_svector_ostream Result;
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000338};
339} // end unnamed namespace
340
341void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
342 appendToResultWithHTMLEscaping(C->getText());
343}
344
345void CommentASTToHTMLConverter::visitInlineCommandComment(
346 const InlineCommandComment *C) {
347 StringRef CommandName = C->getCommandName();
348 bool HasArg0 = C->getNumArgs() > 0 && !C->getArgText(0).empty();
349 StringRef Arg0;
350 if (HasArg0)
351 Arg0 = C->getArgText(0);
352
353 if (CommandName == "b") {
354 if (!HasArg0)
355 return;
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000356 Result << "<b>" << Arg0 << "</b>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000357 return;
358 }
359 if (CommandName == "c" || CommandName == "p") {
360 if (!HasArg0)
361 return;
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000362 Result << "<tt>" << Arg0 << "</tt>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000363 return;
364 }
365 if (CommandName == "a" || CommandName == "e" || CommandName == "em") {
366 if (!HasArg0)
367 return;
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000368 Result << "<em>" << Arg0 << "</em>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000369 return;
370 }
371
372 // We don't recognize this command, so just print its arguments.
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000373 for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
374 Result << C->getArgText(i) << " ";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000375}
376
377void CommentASTToHTMLConverter::visitHTMLStartTagComment(
378 const HTMLStartTagComment *C) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000379 Result << "<" << C->getTagName();
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000380
381 if (C->getNumAttrs() != 0) {
382 for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000383 Result << " ";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000384 const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000385 Result << Attr.Name;
386 if (!Attr.Value.empty())
387 Result << "=\"" << Attr.Value << "\"";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000388 }
389 }
390
391 if (!C->isSelfClosing())
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000392 Result << ">";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000393 else
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000394 Result << "/>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000395}
396
397void CommentASTToHTMLConverter::visitHTMLEndTagComment(
398 const HTMLEndTagComment *C) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000399 Result << "</" << C->getTagName() << ">";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000400}
401
402void CommentASTToHTMLConverter::visitParagraphComment(
403 const ParagraphComment *C) {
404 if (C->isWhitespace())
405 return;
406
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000407 Result << "<p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000408 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
409 I != E; ++I) {
410 visit(*I);
411 }
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000412 Result << "</p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000413}
414
415void CommentASTToHTMLConverter::visitBlockCommandComment(
416 const BlockCommandComment *C) {
417 StringRef CommandName = C->getCommandName();
418 if (CommandName == "brief" || CommandName == "short") {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000419 Result << "<p class=\"para-brief\">";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000420 visitNonStandaloneParagraphComment(C->getParagraph());
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000421 Result << "</p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000422 return;
423 }
424 if (CommandName == "returns" || CommandName == "return") {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000425 Result << "<p class=\"para-returns\">"
426 "<span class=\"word-returns\">Returns</span> ";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000427 visitNonStandaloneParagraphComment(C->getParagraph());
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000428 Result << "</p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000429 return;
430 }
431 // We don't know anything about this command. Just render the paragraph.
432 visit(C->getParagraph());
433}
434
435void CommentASTToHTMLConverter::visitParamCommandComment(
436 const ParamCommandComment *C) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000437 if (C->isParamIndexValid()) {
438 Result << "<dt class=\"param-name-index-"
439 << C->getParamIndex()
440 << "\">";
441 } else
442 Result << "<dt class=\"param-name-index-invalid\">";
443
444 Result << C->getParamName() << "</dt>";
445
446 if (C->isParamIndexValid()) {
447 Result << "<dd class=\"param-descr-index-"
448 << C->getParamIndex()
449 << "\">";
450 } else
451 Result << "<dd class=\"param-descr-index-invalid\">";
452
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000453 visitNonStandaloneParagraphComment(C->getParagraph());
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000454 Result << "</dd>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000455}
456
457void CommentASTToHTMLConverter::visitVerbatimBlockComment(
458 const VerbatimBlockComment *C) {
459 unsigned NumLines = C->getNumLines();
460 if (NumLines == 0)
461 return;
462
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000463 Result << "<pre>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000464 for (unsigned i = 0; i != NumLines; ++i) {
465 appendToResultWithHTMLEscaping(C->getText(i));
466 if (i + 1 != NumLines)
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000467 Result << '\n';
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000468 }
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000469 Result << "</pre>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000470}
471
472void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
473 const VerbatimBlockLineComment *C) {
474 llvm_unreachable("should not see this AST node");
475}
476
477void CommentASTToHTMLConverter::visitVerbatimLineComment(
478 const VerbatimLineComment *C) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000479 Result << "<pre>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000480 appendToResultWithHTMLEscaping(C->getText());
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000481 Result << "</pre>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000482}
483
484void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
485 const BlockContentComment *Brief = NULL;
486 const ParagraphComment *FirstParagraph = NULL;
487 const BlockCommandComment *Returns = NULL;
488 SmallVector<const ParamCommandComment *, 8> Params;
489 SmallVector<const BlockContentComment *, 8> MiscBlocks;
490
491 // Extract various blocks into separate variables and vectors above.
492 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
493 I != E; ++I) {
494 const Comment *Child = *I;
495 if (!Child)
496 continue;
497 switch (Child->getCommentKind()) {
498 case Comment::NoCommentKind:
499 continue;
500
501 case Comment::ParagraphCommentKind: {
502 const ParagraphComment *PC = cast<ParagraphComment>(Child);
503 if (PC->isWhitespace())
504 break;
505 if (!FirstParagraph)
506 FirstParagraph = PC;
507
508 MiscBlocks.push_back(PC);
509 break;
510 }
511
512 case Comment::BlockCommandCommentKind: {
513 const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
514 StringRef CommandName = BCC->getCommandName();
515 if (!Brief && (CommandName == "brief" || CommandName == "short")) {
516 Brief = BCC;
517 break;
518 }
519 if (!Returns && (CommandName == "returns" || CommandName == "return")) {
520 Returns = BCC;
521 break;
522 }
523 MiscBlocks.push_back(BCC);
524 break;
525 }
526
527 case Comment::ParamCommandCommentKind: {
528 const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
529 if (!PCC->hasParamName())
530 break;
531
532 if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
533 break;
534
535 Params.push_back(PCC);
536 break;
537 }
538
539 case Comment::VerbatimBlockCommentKind:
540 case Comment::VerbatimLineCommentKind:
541 MiscBlocks.push_back(cast<BlockCommandComment>(Child));
542 break;
543
544 case Comment::TextCommentKind:
545 case Comment::InlineCommandCommentKind:
546 case Comment::HTMLStartTagCommentKind:
547 case Comment::HTMLEndTagCommentKind:
548 case Comment::VerbatimBlockLineCommentKind:
549 case Comment::FullCommentKind:
550 llvm_unreachable("AST node of this kind can't be a child of "
551 "a FullComment");
552 }
553 }
554
555 // Sort params in order they are declared in the function prototype.
556 // Unresolved parameters are put at the end of the list in the same order
557 // they were seen in the comment.
558 std::stable_sort(Params.begin(), Params.end(),
559 ParamCommandCommentCompareIndex());
560
561 bool FirstParagraphIsBrief = false;
562 if (Brief)
563 visit(Brief);
564 else if (FirstParagraph) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000565 Result << "<p class=\"para-brief\">";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000566 visitNonStandaloneParagraphComment(FirstParagraph);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000567 Result << "</p>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000568 FirstParagraphIsBrief = true;
569 }
570
571 for (unsigned i = 0, e = MiscBlocks.size(); i != e; ++i) {
572 const Comment *C = MiscBlocks[i];
573 if (FirstParagraphIsBrief && C == FirstParagraph)
574 continue;
575 visit(C);
576 }
577
578 if (Params.size() != 0) {
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000579 Result << "<dl>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000580 for (unsigned i = 0, e = Params.size(); i != e; ++i)
581 visit(Params[i]);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000582 Result << "</dl>";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000583 }
584
585 if (Returns)
586 visit(Returns);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000587
588 Result.flush();
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000589}
590
591void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
592 const ParagraphComment *C) {
593 if (!C)
594 return;
595
596 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
597 I != E; ++I) {
598 visit(*I);
599 }
600}
601
602void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000603 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
604 const char C = *I;
605 switch (C) {
606 case '&':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000607 Result << "&amp;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000608 break;
609 case '<':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000610 Result << "&lt;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000611 break;
612 case '>':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000613 Result << "&gt;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000614 break;
615 case '"':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000616 Result << "&quot;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000617 break;
618 case '\'':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000619 Result << "&#39;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000620 break;
621 case '/':
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000622 Result << "&#47;";
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000623 break;
624 default:
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000625 Result << C;
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000626 break;
627 }
628 }
629}
630
631extern "C" {
632
633CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
634 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
635 if (!HTC)
636 return createCXString((const char *) 0);
637
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000638 SmallString<128> HTML;
639 CommentASTToHTMLConverter Converter(HTML);
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000640 Converter.visit(HTC);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000641 return createCXString(HTML.str(), /* DupString = */ true);
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000642}
643
644CXString clang_FullComment_getAsHTML(CXComment CXC) {
645 const FullComment *FC = getASTNodeAs<FullComment>(CXC);
646 if (!FC)
647 return createCXString((const char *) 0);
648
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000649 SmallString<1024> HTML;
650 CommentASTToHTMLConverter Converter(HTML);
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000651 Converter.visit(FC);
Dmitri Gribenko3e63d332012-07-21 01:47:43 +0000652 return createCXString(HTML.str(), /* DupString = */ true);
Dmitri Gribenkoae99b752012-07-20 21:34:34 +0000653}
654
655} // end extern "C"
656