blob: 583b850a44d63cfd1f38734ae34516b23c5b4f8c [file] [log] [blame]
Dmitri Gribenko5e4fe002012-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"
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +000015#include "CXComment.h"
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +000016#include "CXCursor.h"
Chandler Carruthcc0694c2012-12-04 09:25:21 +000017#include "CXString.h"
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +000018#include "SimpleFormatContext.h"
Dmitri Gribenkodcbc8ce2012-08-09 17:33:20 +000019#include "clang/AST/CommentCommandTraits.h"
Chandler Carruthcc0694c2012-12-04 09:25:21 +000020#include "clang/AST/CommentVisitor.h"
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +000021#include "clang/AST/Decl.h"
Chandler Carruthcc0694c2012-12-04 09:25:21 +000022#include "clang/AST/PrettyPrinter.h"
Chandler Carruth44eb4f62013-01-02 10:28:36 +000023#include "clang/Format/Format.h"
24#include "clang/Lex/Lexer.h"
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +000025#include "llvm/ADT/StringExtras.h"
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +000026#include "llvm/ADT/StringSwitch.h"
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +000027#include "llvm/Support/ErrorHandling.h"
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +000028#include "llvm/Support/raw_ostream.h"
Dmitri Gribenko5de4c062012-07-30 17:49:32 +000029#include <climits>
30
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +000031using namespace clang;
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +000032using namespace clang::comments;
33using namespace clang::cxcomment;
34
35extern "C" {
36
37enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
38 const Comment *C = getASTNode(CXC);
39 if (!C)
40 return CXComment_Null;
41
42 switch (C->getCommentKind()) {
43 case Comment::NoCommentKind:
44 return CXComment_Null;
45
46 case Comment::TextCommentKind:
47 return CXComment_Text;
48
49 case Comment::InlineCommandCommentKind:
50 return CXComment_InlineCommand;
51
52 case Comment::HTMLStartTagCommentKind:
53 return CXComment_HTMLStartTag;
54
55 case Comment::HTMLEndTagCommentKind:
56 return CXComment_HTMLEndTag;
57
58 case Comment::ParagraphCommentKind:
59 return CXComment_Paragraph;
60
61 case Comment::BlockCommandCommentKind:
62 return CXComment_BlockCommand;
63
64 case Comment::ParamCommandCommentKind:
65 return CXComment_ParamCommand;
66
Dmitri Gribenko34df2202012-07-31 22:37:06 +000067 case Comment::TParamCommandCommentKind:
68 return CXComment_TParamCommand;
69
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +000070 case Comment::VerbatimBlockCommentKind:
71 return CXComment_VerbatimBlockCommand;
72
73 case Comment::VerbatimBlockLineCommentKind:
74 return CXComment_VerbatimBlockLine;
75
76 case Comment::VerbatimLineCommentKind:
77 return CXComment_VerbatimLine;
78
79 case Comment::FullCommentKind:
80 return CXComment_FullComment;
81 }
82 llvm_unreachable("unknown CommentKind");
83}
84
85unsigned clang_Comment_getNumChildren(CXComment CXC) {
86 const Comment *C = getASTNode(CXC);
87 if (!C)
88 return 0;
89
90 return C->child_count();
91}
92
93CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
94 const Comment *C = getASTNode(CXC);
95 if (!C || ChildIdx >= C->child_count())
Dmitri Gribenko7acbf002012-09-10 20:32:42 +000096 return createCXComment(NULL, NULL);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +000097
Dmitri Gribenko7acbf002012-09-10 20:32:42 +000098 return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +000099}
100
101unsigned clang_Comment_isWhitespace(CXComment CXC) {
102 const Comment *C = getASTNode(CXC);
103 if (!C)
104 return false;
105
106 if (const TextComment *TC = dyn_cast<TextComment>(C))
107 return TC->isWhitespace();
108
109 if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
110 return PC->isWhitespace();
111
112 return false;
113}
114
115unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
116 const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
117 if (!ICC)
118 return false;
119
120 return ICC->hasTrailingNewline();
121}
122
123CXString clang_TextComment_getText(CXComment CXC) {
124 const TextComment *TC = getASTNodeAs<TextComment>(CXC);
125 if (!TC)
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000126 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000127
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000128 return cxstring::createRef(TC->getText());
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000129}
130
131CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
132 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
133 if (!ICC)
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000134 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000135
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000136 const CommandTraits &Traits = getCommandTraits(CXC);
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000137 return cxstring::createRef(ICC->getCommandName(Traits));
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000138}
139
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000140enum CXCommentInlineCommandRenderKind
141clang_InlineCommandComment_getRenderKind(CXComment CXC) {
142 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
143 if (!ICC)
144 return CXCommentInlineCommandRenderKind_Normal;
145
146 switch (ICC->getRenderKind()) {
147 case InlineCommandComment::RenderNormal:
148 return CXCommentInlineCommandRenderKind_Normal;
149
150 case InlineCommandComment::RenderBold:
151 return CXCommentInlineCommandRenderKind_Bold;
152
153 case InlineCommandComment::RenderMonospaced:
154 return CXCommentInlineCommandRenderKind_Monospaced;
155
156 case InlineCommandComment::RenderEmphasized:
157 return CXCommentInlineCommandRenderKind_Emphasized;
158 }
159 llvm_unreachable("unknown InlineCommandComment::RenderKind");
160}
161
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000162unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
163 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
164 if (!ICC)
165 return 0;
166
167 return ICC->getNumArgs();
168}
169
170CXString clang_InlineCommandComment_getArgText(CXComment CXC,
171 unsigned ArgIdx) {
172 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
173 if (!ICC || ArgIdx >= ICC->getNumArgs())
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000174 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000175
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000176 return cxstring::createRef(ICC->getArgText(ArgIdx));
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000177}
178
179CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
180 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
181 if (!HTC)
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000182 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000183
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000184 return cxstring::createRef(HTC->getTagName());
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000185}
186
187unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
188 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
189 if (!HST)
190 return false;
191
192 return HST->isSelfClosing();
193}
194
195unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
196 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
197 if (!HST)
198 return 0;
199
200 return HST->getNumAttrs();
201}
202
203CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
204 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
205 if (!HST || AttrIdx >= HST->getNumAttrs())
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000206 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000207
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000208 return cxstring::createRef(HST->getAttr(AttrIdx).Name);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000209}
210
211CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
212 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
213 if (!HST || AttrIdx >= HST->getNumAttrs())
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000214 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000215
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000216 return cxstring::createRef(HST->getAttr(AttrIdx).Value);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000217}
218
219CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
220 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
221 if (!BCC)
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000222 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000223
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000224 const CommandTraits &Traits = getCommandTraits(CXC);
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000225 return cxstring::createRef(BCC->getCommandName(Traits));
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000226}
227
228unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
229 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
230 if (!BCC)
231 return 0;
232
233 return BCC->getNumArgs();
234}
235
236CXString clang_BlockCommandComment_getArgText(CXComment CXC,
237 unsigned ArgIdx) {
238 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
239 if (!BCC || ArgIdx >= BCC->getNumArgs())
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000240 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000241
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000242 return cxstring::createRef(BCC->getArgText(ArgIdx));
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000243}
244
245CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
246 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
247 if (!BCC)
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000248 return createCXComment(NULL, NULL);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000249
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000250 return createCXComment(BCC->getParagraph(), CXC.TranslationUnit);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000251}
252
253CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
254 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
Dmitri Gribenko378458d2012-07-23 19:41:49 +0000255 if (!PCC || !PCC->hasParamName())
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000256 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000257
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000258 return cxstring::createRef(PCC->getParamNameAsWritten());
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000259}
260
261unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
262 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
263 if (!PCC)
264 return false;
265
266 return PCC->isParamIndexValid();
267}
268
269unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
270 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
Dmitri Gribenkoa260c032012-07-30 17:38:19 +0000271 if (!PCC || !PCC->isParamIndexValid())
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000272 return ParamCommandComment::InvalidParamIndex;
273
274 return PCC->getParamIndex();
275}
276
277unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
278 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
279 if (!PCC)
280 return false;
281
282 return PCC->isDirectionExplicit();
283}
284
285enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
286 CXComment CXC) {
287 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
288 if (!PCC)
289 return CXCommentParamPassDirection_In;
290
291 switch (PCC->getDirection()) {
292 case ParamCommandComment::In:
293 return CXCommentParamPassDirection_In;
294
295 case ParamCommandComment::Out:
296 return CXCommentParamPassDirection_Out;
297
298 case ParamCommandComment::InOut:
299 return CXCommentParamPassDirection_InOut;
300 }
301 llvm_unreachable("unknown ParamCommandComment::PassDirection");
302}
303
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000304CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
305 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
306 if (!TPCC || !TPCC->hasParamName())
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000307 return cxstring::createNull();
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000308
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000309 return cxstring::createRef(TPCC->getParamNameAsWritten());
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000310}
311
312unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
313 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
314 if (!TPCC)
315 return false;
316
317 return TPCC->isPositionValid();
318}
319
320unsigned clang_TParamCommandComment_getDepth(CXComment CXC) {
321 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
322 if (!TPCC || !TPCC->isPositionValid())
323 return 0;
324
325 return TPCC->getDepth();
326}
327
328unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) {
329 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
330 if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth())
331 return 0;
332
333 return TPCC->getIndex(Depth);
334}
335
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000336CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
337 const VerbatimBlockLineComment *VBL =
338 getASTNodeAs<VerbatimBlockLineComment>(CXC);
339 if (!VBL)
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000340 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000341
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000342 return cxstring::createRef(VBL->getText());
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000343}
344
345CXString clang_VerbatimLineComment_getText(CXComment CXC) {
346 const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
347 if (!VLC)
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000348 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000349
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000350 return cxstring::createRef(VLC->getText());
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000351}
352
353} // end extern "C"
354
355//===----------------------------------------------------------------------===//
356// Helpers for converting comment AST to HTML.
357//===----------------------------------------------------------------------===//
358
359namespace {
360
Dmitri Gribenko3af5f732012-07-30 19:47:34 +0000361/// This comparison will sort parameters with valid index by index and
362/// invalid (unresolved) parameters last.
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000363class ParamCommandCommentCompareIndex {
364public:
365 bool operator()(const ParamCommandComment *LHS,
366 const ParamCommandComment *RHS) const {
Dmitri Gribenkoa260c032012-07-30 17:38:19 +0000367 unsigned LHSIndex = UINT_MAX;
368 unsigned RHSIndex = UINT_MAX;
369 if (LHS->isParamIndexValid())
370 LHSIndex = LHS->getParamIndex();
371 if (RHS->isParamIndexValid())
372 RHSIndex = RHS->getParamIndex();
373
374 return LHSIndex < RHSIndex;
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000375 }
376};
377
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000378/// This comparison will sort template parameters in the following order:
379/// \li real template parameters (depth = 1) in index order;
380/// \li all other names (depth > 1);
381/// \li unresolved names.
382class TParamCommandCommentComparePosition {
383public:
384 bool operator()(const TParamCommandComment *LHS,
385 const TParamCommandComment *RHS) const {
386 // Sort unresolved names last.
387 if (!LHS->isPositionValid())
388 return false;
389 if (!RHS->isPositionValid())
390 return true;
391
392 if (LHS->getDepth() > 1)
393 return false;
394 if (RHS->getDepth() > 1)
395 return true;
396
397 // Sort template parameters in index order.
398 if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
399 return LHS->getIndex(0) < RHS->getIndex(0);
400
401 // Leave all other names in source order.
402 return true;
403 }
404};
405
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000406/// Separate parts of a FullComment.
407struct FullCommentParts {
408 /// Take a full comment apart and initialize members accordingly.
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000409 FullCommentParts(const FullComment *C,
410 const CommandTraits &Traits);
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000411
412 const BlockContentComment *Brief;
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +0000413 const BlockContentComment *Headerfile;
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000414 const ParagraphComment *FirstParagraph;
Fariborz Jahanianfb6f6f62013-06-21 23:49:29 +0000415 SmallVector<const BlockCommandComment *, 4> Returns;
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000416 SmallVector<const ParamCommandComment *, 8> Params;
417 SmallVector<const TParamCommandComment *, 4> TParams;
418 SmallVector<const BlockContentComment *, 8> MiscBlocks;
419};
420
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000421FullCommentParts::FullCommentParts(const FullComment *C,
422 const CommandTraits &Traits) :
Fariborz Jahanianfb6f6f62013-06-21 23:49:29 +0000423 Brief(NULL), Headerfile(NULL), FirstParagraph(NULL) {
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000424 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
425 I != E; ++I) {
426 const Comment *Child = *I;
427 if (!Child)
428 continue;
429 switch (Child->getCommentKind()) {
430 case Comment::NoCommentKind:
431 continue;
432
433 case Comment::ParagraphCommentKind: {
434 const ParagraphComment *PC = cast<ParagraphComment>(Child);
435 if (PC->isWhitespace())
436 break;
437 if (!FirstParagraph)
438 FirstParagraph = PC;
439
440 MiscBlocks.push_back(PC);
441 break;
442 }
443
444 case Comment::BlockCommandCommentKind: {
445 const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000446 const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
447 if (!Brief && Info->IsBriefCommand) {
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000448 Brief = BCC;
449 break;
450 }
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +0000451 if (!Headerfile && Info->IsHeaderfileCommand) {
452 Headerfile = BCC;
453 break;
454 }
Fariborz Jahanianfb6f6f62013-06-21 23:49:29 +0000455 if (Info->IsReturnsCommand) {
456 Returns.push_back(BCC);
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000457 break;
458 }
459 MiscBlocks.push_back(BCC);
460 break;
461 }
462
463 case Comment::ParamCommandCommentKind: {
464 const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
465 if (!PCC->hasParamName())
466 break;
467
468 if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
469 break;
470
471 Params.push_back(PCC);
472 break;
473 }
474
475 case Comment::TParamCommandCommentKind: {
476 const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
477 if (!TPCC->hasParamName())
478 break;
479
480 if (!TPCC->hasNonWhitespaceParagraph())
481 break;
482
483 TParams.push_back(TPCC);
484 break;
485 }
486
487 case Comment::VerbatimBlockCommentKind:
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000488 MiscBlocks.push_back(cast<BlockCommandComment>(Child));
489 break;
490
Dmitri Gribenkoba7aca32012-08-09 18:20:29 +0000491 case Comment::VerbatimLineCommentKind: {
492 const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000493 const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
494 if (!Info->IsDeclarationCommand)
Dmitri Gribenkoba7aca32012-08-09 18:20:29 +0000495 MiscBlocks.push_back(VLC);
496 break;
497 }
498
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000499 case Comment::TextCommentKind:
500 case Comment::InlineCommandCommentKind:
501 case Comment::HTMLStartTagCommentKind:
502 case Comment::HTMLEndTagCommentKind:
503 case Comment::VerbatimBlockLineCommentKind:
504 case Comment::FullCommentKind:
505 llvm_unreachable("AST node of this kind can't be a child of "
506 "a FullComment");
507 }
508 }
509
510 // Sort params in order they are declared in the function prototype.
511 // Unresolved parameters are put at the end of the list in the same order
512 // they were seen in the comment.
513 std::stable_sort(Params.begin(), Params.end(),
514 ParamCommandCommentCompareIndex());
515
516 std::stable_sort(TParams.begin(), TParams.end(),
517 TParamCommandCommentComparePosition());
518}
519
520void PrintHTMLStartTagComment(const HTMLStartTagComment *C,
521 llvm::raw_svector_ostream &Result) {
522 Result << "<" << C->getTagName();
523
524 if (C->getNumAttrs() != 0) {
525 for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
526 Result << " ";
527 const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
528 Result << Attr.Name;
529 if (!Attr.Value.empty())
530 Result << "=\"" << Attr.Value << "\"";
531 }
532 }
533
534 if (!C->isSelfClosing())
535 Result << ">";
536 else
537 Result << "/>";
538}
539
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000540class CommentASTToHTMLConverter :
541 public ConstCommentVisitor<CommentASTToHTMLConverter> {
542public:
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000543 /// \param Str accumulator for HTML.
Dmitri Gribenko923f3052012-10-19 16:51:38 +0000544 CommentASTToHTMLConverter(const FullComment *FC,
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000545 SmallVectorImpl<char> &Str,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000546 const CommandTraits &Traits) :
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000547 FC(FC), Result(Str), Traits(Traits)
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000548 { }
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000549
550 // Inline content.
551 void visitTextComment(const TextComment *C);
552 void visitInlineCommandComment(const InlineCommandComment *C);
553 void visitHTMLStartTagComment(const HTMLStartTagComment *C);
554 void visitHTMLEndTagComment(const HTMLEndTagComment *C);
555
556 // Block content.
557 void visitParagraphComment(const ParagraphComment *C);
558 void visitBlockCommandComment(const BlockCommandComment *C);
559 void visitParamCommandComment(const ParamCommandComment *C);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000560 void visitTParamCommandComment(const TParamCommandComment *C);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000561 void visitVerbatimBlockComment(const VerbatimBlockComment *C);
562 void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
563 void visitVerbatimLineComment(const VerbatimLineComment *C);
564
565 void visitFullComment(const FullComment *C);
566
567 // Helpers.
568
569 /// Convert a paragraph that is not a block by itself (an argument to some
570 /// command).
571 void visitNonStandaloneParagraphComment(const ParagraphComment *C);
572
573 void appendToResultWithHTMLEscaping(StringRef S);
574
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000575private:
Dmitri Gribenko923f3052012-10-19 16:51:38 +0000576 const FullComment *FC;
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000577 /// Output stream for HTML.
578 llvm::raw_svector_ostream Result;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000579
580 const CommandTraits &Traits;
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000581};
582} // end unnamed namespace
583
584void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
585 appendToResultWithHTMLEscaping(C->getText());
586}
587
588void CommentASTToHTMLConverter::visitInlineCommandComment(
589 const InlineCommandComment *C) {
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000590 // Nothing to render if no arguments supplied.
591 if (C->getNumArgs() == 0)
592 return;
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000593
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000594 // Nothing to render if argument is empty.
595 StringRef Arg0 = C->getArgText(0);
596 if (Arg0.empty())
597 return;
598
599 switch (C->getRenderKind()) {
600 case InlineCommandComment::RenderNormal:
Dmitri Gribenko7c0456f2012-08-01 00:21:12 +0000601 for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
602 appendToResultWithHTMLEscaping(C->getArgText(i));
603 Result << " ";
604 }
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000605 return;
606
607 case InlineCommandComment::RenderBold:
608 assert(C->getNumArgs() == 1);
Dmitri Gribenko7c0456f2012-08-01 00:21:12 +0000609 Result << "<b>";
610 appendToResultWithHTMLEscaping(Arg0);
611 Result << "</b>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000612 return;
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000613 case InlineCommandComment::RenderMonospaced:
614 assert(C->getNumArgs() == 1);
Dmitri Gribenko7c0456f2012-08-01 00:21:12 +0000615 Result << "<tt>";
616 appendToResultWithHTMLEscaping(Arg0);
617 Result<< "</tt>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000618 return;
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000619 case InlineCommandComment::RenderEmphasized:
620 assert(C->getNumArgs() == 1);
Dmitri Gribenko7c0456f2012-08-01 00:21:12 +0000621 Result << "<em>";
622 appendToResultWithHTMLEscaping(Arg0);
623 Result << "</em>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000624 return;
625 }
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000626}
627
628void CommentASTToHTMLConverter::visitHTMLStartTagComment(
629 const HTMLStartTagComment *C) {
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000630 PrintHTMLStartTagComment(C, Result);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000631}
632
633void CommentASTToHTMLConverter::visitHTMLEndTagComment(
634 const HTMLEndTagComment *C) {
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000635 Result << "</" << C->getTagName() << ">";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000636}
637
638void CommentASTToHTMLConverter::visitParagraphComment(
639 const ParagraphComment *C) {
640 if (C->isWhitespace())
641 return;
642
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000643 Result << "<p>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000644 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
645 I != E; ++I) {
646 visit(*I);
647 }
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000648 Result << "</p>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000649}
650
651void CommentASTToHTMLConverter::visitBlockCommandComment(
652 const BlockCommandComment *C) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000653 const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
654 if (Info->IsBriefCommand) {
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000655 Result << "<p class=\"para-brief\">";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000656 visitNonStandaloneParagraphComment(C->getParagraph());
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000657 Result << "</p>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000658 return;
659 }
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000660 if (Info->IsReturnsCommand) {
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000661 Result << "<p class=\"para-returns\">"
662 "<span class=\"word-returns\">Returns</span> ";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000663 visitNonStandaloneParagraphComment(C->getParagraph());
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000664 Result << "</p>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000665 return;
666 }
667 // We don't know anything about this command. Just render the paragraph.
668 visit(C->getParagraph());
669}
670
671void CommentASTToHTMLConverter::visitParamCommandComment(
672 const ParamCommandComment *C) {
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000673 if (C->isParamIndexValid()) {
674 Result << "<dt class=\"param-name-index-"
675 << C->getParamIndex()
676 << "\">";
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +0000677 appendToResultWithHTMLEscaping(C->getParamName(FC));
678 } else {
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000679 Result << "<dt class=\"param-name-index-invalid\">";
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +0000680 appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
681 }
Dmitri Gribenko7c0456f2012-08-01 00:21:12 +0000682 Result << "</dt>";
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000683
684 if (C->isParamIndexValid()) {
685 Result << "<dd class=\"param-descr-index-"
686 << C->getParamIndex()
687 << "\">";
688 } else
689 Result << "<dd class=\"param-descr-index-invalid\">";
690
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000691 visitNonStandaloneParagraphComment(C->getParagraph());
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000692 Result << "</dd>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000693}
694
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000695void CommentASTToHTMLConverter::visitTParamCommandComment(
696 const TParamCommandComment *C) {
697 if (C->isPositionValid()) {
698 if (C->getDepth() == 1)
Dmitri Gribenko58e41312012-08-01 23:47:30 +0000699 Result << "<dt class=\"tparam-name-index-"
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000700 << C->getIndex(0)
701 << "\">";
702 else
Dmitri Gribenko58e41312012-08-01 23:47:30 +0000703 Result << "<dt class=\"tparam-name-index-other\">";
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +0000704 appendToResultWithHTMLEscaping(C->getParamName(FC));
705 } else {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000706 Result << "<dt class=\"tparam-name-index-invalid\">";
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +0000707 appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
708 }
709
Dmitri Gribenko7c0456f2012-08-01 00:21:12 +0000710 Result << "</dt>";
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000711
712 if (C->isPositionValid()) {
713 if (C->getDepth() == 1)
714 Result << "<dd class=\"tparam-descr-index-"
715 << C->getIndex(0)
716 << "\">";
717 else
718 Result << "<dd class=\"tparam-descr-index-other\">";
719 } else
720 Result << "<dd class=\"tparam-descr-index-invalid\">";
721
722 visitNonStandaloneParagraphComment(C->getParagraph());
723 Result << "</dd>";
724}
725
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000726void CommentASTToHTMLConverter::visitVerbatimBlockComment(
727 const VerbatimBlockComment *C) {
728 unsigned NumLines = C->getNumLines();
729 if (NumLines == 0)
730 return;
731
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000732 Result << "<pre>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000733 for (unsigned i = 0; i != NumLines; ++i) {
734 appendToResultWithHTMLEscaping(C->getText(i));
735 if (i + 1 != NumLines)
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000736 Result << '\n';
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000737 }
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000738 Result << "</pre>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000739}
740
741void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
742 const VerbatimBlockLineComment *C) {
743 llvm_unreachable("should not see this AST node");
744}
745
746void CommentASTToHTMLConverter::visitVerbatimLineComment(
747 const VerbatimLineComment *C) {
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000748 Result << "<pre>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000749 appendToResultWithHTMLEscaping(C->getText());
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000750 Result << "</pre>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000751}
752
753void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000754 FullCommentParts Parts(C, Traits);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000755
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000756 bool FirstParagraphIsBrief = false;
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +0000757 if (Parts.Headerfile)
758 visit(Parts.Headerfile);
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000759 if (Parts.Brief)
760 visit(Parts.Brief);
761 else if (Parts.FirstParagraph) {
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000762 Result << "<p class=\"para-brief\">";
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000763 visitNonStandaloneParagraphComment(Parts.FirstParagraph);
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000764 Result << "</p>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000765 FirstParagraphIsBrief = true;
766 }
767
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000768 for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
769 const Comment *C = Parts.MiscBlocks[i];
770 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000771 continue;
772 visit(C);
773 }
774
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000775 if (Parts.TParams.size() != 0) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000776 Result << "<dl>";
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000777 for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
778 visit(Parts.TParams[i]);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000779 Result << "</dl>";
780 }
781
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000782 if (Parts.Params.size() != 0) {
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000783 Result << "<dl>";
Dmitri Gribenko3a770d02012-08-01 22:48:16 +0000784 for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
785 visit(Parts.Params[i]);
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000786 Result << "</dl>";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000787 }
788
Fariborz Jahanianfb6f6f62013-06-21 23:49:29 +0000789 if (Parts.Returns.size() != 0) {
Dmitri Gribenkod6662932013-06-22 23:03:37 +0000790 Result << "<div class=\"result-discussion\">";
Fariborz Jahanianfb6f6f62013-06-21 23:49:29 +0000791 for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
792 visit(Parts.Returns[i]);
Dmitri Gribenkod6662932013-06-22 23:03:37 +0000793 Result << "</div>";
Fariborz Jahanianfb6f6f62013-06-21 23:49:29 +0000794 }
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000795
796 Result.flush();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000797}
798
799void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
800 const ParagraphComment *C) {
801 if (!C)
802 return;
803
804 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
805 I != E; ++I) {
806 visit(*I);
807 }
808}
809
810void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000811 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
812 const char C = *I;
813 switch (C) {
814 case '&':
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000815 Result << "&amp;";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000816 break;
817 case '<':
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000818 Result << "&lt;";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000819 break;
820 case '>':
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000821 Result << "&gt;";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000822 break;
823 case '"':
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000824 Result << "&quot;";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000825 break;
826 case '\'':
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000827 Result << "&#39;";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000828 break;
829 case '/':
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000830 Result << "&#47;";
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000831 break;
832 default:
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000833 Result << C;
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000834 break;
835 }
836 }
837}
838
839extern "C" {
840
841CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
842 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
843 if (!HTC)
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000844 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000845
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000846 SmallString<128> HTML;
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000847 CommentASTToHTMLConverter Converter(0, HTML, getCommandTraits(CXC));
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000848 Converter.visit(HTC);
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000849 return cxstring::createDup(HTML.str());
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000850}
851
852CXString clang_FullComment_getAsHTML(CXComment CXC) {
853 const FullComment *FC = getASTNodeAs<FullComment>(CXC);
854 if (!FC)
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +0000855 return cxstring::createNull();
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000856
Dmitri Gribenko4c6d7a22012-07-21 01:47:43 +0000857 SmallString<1024> HTML;
Dmitri Gribenko923f3052012-10-19 16:51:38 +0000858 CommentASTToHTMLConverter Converter(FC, HTML, getCommandTraits(CXC));
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000859 Converter.visit(FC);
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +0000860 return cxstring::createDup(HTML.str());
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000861}
862
863} // end extern "C"
864
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000865namespace {
866class CommentASTToXMLConverter :
867 public ConstCommentVisitor<CommentASTToXMLConverter> {
868public:
869 /// \param Str accumulator for XML.
Dmitri Gribenko923f3052012-10-19 16:51:38 +0000870 CommentASTToXMLConverter(const FullComment *FC,
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000871 SmallVectorImpl<char> &Str,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000872 const CommandTraits &Traits,
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +0000873 const SourceManager &SM,
Fariborz Jahanianb67908a2012-12-19 00:01:48 +0000874 SimpleFormatContext &SFC,
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +0000875 unsigned FUID) :
876 FC(FC), Result(Str), Traits(Traits), SM(SM),
Fariborz Jahanianb67908a2012-12-19 00:01:48 +0000877 FormatRewriterContext(SFC),
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +0000878 FormatInMemoryUniqueId(FUID) { }
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000879
880 // Inline content.
881 void visitTextComment(const TextComment *C);
882 void visitInlineCommandComment(const InlineCommandComment *C);
883 void visitHTMLStartTagComment(const HTMLStartTagComment *C);
884 void visitHTMLEndTagComment(const HTMLEndTagComment *C);
885
886 // Block content.
887 void visitParagraphComment(const ParagraphComment *C);
Dmitri Gribenko2e72dd42013-02-01 20:23:57 +0000888
889 void appendParagraphCommentWithKind(const ParagraphComment *C,
890 StringRef Kind);
891
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000892 void visitBlockCommandComment(const BlockCommandComment *C);
893 void visitParamCommandComment(const ParamCommandComment *C);
894 void visitTParamCommandComment(const TParamCommandComment *C);
895 void visitVerbatimBlockComment(const VerbatimBlockComment *C);
896 void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
897 void visitVerbatimLineComment(const VerbatimLineComment *C);
898
899 void visitFullComment(const FullComment *C);
900
901 // Helpers.
902 void appendToResultWithXMLEscaping(StringRef S);
Dmitri Gribenko2e72dd42013-02-01 20:23:57 +0000903
Fariborz Jahanianb67908a2012-12-19 00:01:48 +0000904 void formatTextOfDeclaration(const DeclInfo *DI,
905 SmallString<128> &Declaration);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000906
907private:
Dmitri Gribenko923f3052012-10-19 16:51:38 +0000908 const FullComment *FC;
909
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000910 /// Output stream for XML.
911 llvm::raw_svector_ostream Result;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000912
913 const CommandTraits &Traits;
914 const SourceManager &SM;
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +0000915 SimpleFormatContext &FormatRewriterContext;
916 unsigned FormatInMemoryUniqueId;
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000917};
Dmitri Gribenko1c1395e2012-10-25 18:28:26 +0000918
919void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
920 SmallVectorImpl<char> &Str) {
921 ASTContext &Context = ThisDecl->CurrentDecl->getASTContext();
922 const LangOptions &LangOpts = Context.getLangOpts();
923 llvm::raw_svector_ostream OS(Str);
924 PrintingPolicy PPolicy(LangOpts);
Fariborz Jahanian0389e522012-12-19 23:36:00 +0000925 PPolicy.PolishForDeclaration = true;
Dmitri Gribenko1c1395e2012-10-25 18:28:26 +0000926 PPolicy.TerseOutput = true;
927 ThisDecl->CurrentDecl->print(OS, PPolicy,
Dmitri Gribenkoa9cc2492013-01-07 18:45:48 +0000928 /*Indentation*/0, /*PrintInstantiation*/false);
Dmitri Gribenko1c1395e2012-10-25 18:28:26 +0000929}
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +0000930
Fariborz Jahanianb67908a2012-12-19 00:01:48 +0000931void CommentASTToXMLConverter::formatTextOfDeclaration(
932 const DeclInfo *DI,
933 SmallString<128> &Declaration) {
Fariborz Jahanianb67908a2012-12-19 00:01:48 +0000934 // FIXME. formatting API expects null terminated input string.
935 // There might be more efficient way of doing this.
936 std::string StringDecl = Declaration.str();
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +0000937
Fariborz Jahanianb67908a2012-12-19 00:01:48 +0000938 // Formatter specific code.
939 // Form a unique in memory buffer name.
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000940 SmallString<128> filename;
Fariborz Jahanianb67908a2012-12-19 00:01:48 +0000941 filename += "xmldecl";
942 filename += llvm::utostr(FormatInMemoryUniqueId);
943 filename += ".xd";
944 FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
945 SourceLocation Start =
946 FormatRewriterContext.Sources.getLocForStartOfFile(ID).getLocWithOffset(0);
947 unsigned Length = Declaration.size();
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +0000948
Fariborz Jahanianb67908a2012-12-19 00:01:48 +0000949 std::vector<CharSourceRange>
950 Ranges(1, CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
951 ASTContext &Context = DI->CurrentDecl->getASTContext();
952 const LangOptions &LangOpts = Context.getLangOpts();
953 Lexer Lex(ID, FormatRewriterContext.Sources.getBuffer(ID),
954 FormatRewriterContext.Sources, LangOpts);
955 tooling::Replacements Replace =
956 reformat(format::getLLVMStyle(), Lex, FormatRewriterContext.Sources, Ranges);
957 applyAllReplacements(Replace, FormatRewriterContext.Rewrite);
958 Declaration = FormatRewriterContext.getRewrittenText(ID);
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +0000959}
Dmitri Gribenko1c1395e2012-10-25 18:28:26 +0000960
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000961} // end unnamed namespace
962
963void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
964 appendToResultWithXMLEscaping(C->getText());
965}
966
967void CommentASTToXMLConverter::visitInlineCommandComment(const InlineCommandComment *C) {
968 // Nothing to render if no arguments supplied.
969 if (C->getNumArgs() == 0)
970 return;
971
972 // Nothing to render if argument is empty.
973 StringRef Arg0 = C->getArgText(0);
974 if (Arg0.empty())
975 return;
976
977 switch (C->getRenderKind()) {
978 case InlineCommandComment::RenderNormal:
979 for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
980 appendToResultWithXMLEscaping(C->getArgText(i));
981 Result << " ";
982 }
983 return;
984 case InlineCommandComment::RenderBold:
985 assert(C->getNumArgs() == 1);
986 Result << "<bold>";
987 appendToResultWithXMLEscaping(Arg0);
988 Result << "</bold>";
989 return;
990 case InlineCommandComment::RenderMonospaced:
991 assert(C->getNumArgs() == 1);
992 Result << "<monospaced>";
993 appendToResultWithXMLEscaping(Arg0);
994 Result << "</monospaced>";
995 return;
996 case InlineCommandComment::RenderEmphasized:
997 assert(C->getNumArgs() == 1);
998 Result << "<emphasized>";
999 appendToResultWithXMLEscaping(Arg0);
1000 Result << "</emphasized>";
1001 return;
1002 }
1003}
1004
1005void CommentASTToXMLConverter::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
1006 Result << "<rawHTML><![CDATA[";
1007 PrintHTMLStartTagComment(C, Result);
1008 Result << "]]></rawHTML>";
1009}
1010
1011void CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
1012 Result << "<rawHTML>&lt;/" << C->getTagName() << "&gt;</rawHTML>";
1013}
1014
1015void CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
Dmitri Gribenko2e72dd42013-02-01 20:23:57 +00001016 appendParagraphCommentWithKind(C, StringRef());
1017}
1018
1019void CommentASTToXMLConverter::appendParagraphCommentWithKind(
1020 const ParagraphComment *C,
1021 StringRef ParagraphKind) {
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001022 if (C->isWhitespace())
1023 return;
1024
Dmitri Gribenko2e72dd42013-02-01 20:23:57 +00001025 if (ParagraphKind.empty())
1026 Result << "<Para>";
1027 else
1028 Result << "<Para kind=\"" << ParagraphKind << "\">";
1029
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001030 for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
1031 I != E; ++I) {
1032 visit(*I);
1033 }
1034 Result << "</Para>";
1035}
1036
1037void CommentASTToXMLConverter::visitBlockCommandComment(const BlockCommandComment *C) {
Dmitri Gribenko2e72dd42013-02-01 20:23:57 +00001038 StringRef ParagraphKind;
1039
1040 switch (C->getCommandID()) {
Fariborz Jahanian828b8d22013-02-26 22:12:16 +00001041 case CommandTraits::KCI_attention:
Dmitri Gribenko2e72dd42013-02-01 20:23:57 +00001042 case CommandTraits::KCI_author:
1043 case CommandTraits::KCI_authors:
1044 case CommandTraits::KCI_bug:
1045 case CommandTraits::KCI_copyright:
1046 case CommandTraits::KCI_date:
1047 case CommandTraits::KCI_invariant:
1048 case CommandTraits::KCI_note:
1049 case CommandTraits::KCI_post:
1050 case CommandTraits::KCI_pre:
1051 case CommandTraits::KCI_remark:
1052 case CommandTraits::KCI_remarks:
1053 case CommandTraits::KCI_sa:
1054 case CommandTraits::KCI_see:
1055 case CommandTraits::KCI_since:
1056 case CommandTraits::KCI_todo:
1057 case CommandTraits::KCI_version:
1058 case CommandTraits::KCI_warning:
1059 ParagraphKind = C->getCommandName(Traits);
1060 default:
1061 break;
1062 }
1063
1064 appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001065}
1066
1067void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandComment *C) {
1068 Result << "<Parameter><Name>";
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +00001069 appendToResultWithXMLEscaping(C->isParamIndexValid() ? C->getParamName(FC)
1070 : C->getParamNameAsWritten());
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001071 Result << "</Name>";
1072
1073 if (C->isParamIndexValid())
1074 Result << "<Index>" << C->getParamIndex() << "</Index>";
1075
1076 Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">";
1077 switch (C->getDirection()) {
1078 case ParamCommandComment::In:
1079 Result << "in";
1080 break;
1081 case ParamCommandComment::Out:
1082 Result << "out";
1083 break;
1084 case ParamCommandComment::InOut:
1085 Result << "in,out";
1086 break;
1087 }
1088 Result << "</Direction><Discussion>";
1089 visit(C->getParagraph());
1090 Result << "</Discussion></Parameter>";
1091}
1092
1093void CommentASTToXMLConverter::visitTParamCommandComment(
1094 const TParamCommandComment *C) {
1095 Result << "<Parameter><Name>";
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +00001096 appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
1097 : C->getParamNameAsWritten());
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001098 Result << "</Name>";
1099
1100 if (C->isPositionValid() && C->getDepth() == 1) {
1101 Result << "<Index>" << C->getIndex(0) << "</Index>";
1102 }
1103
1104 Result << "<Discussion>";
1105 visit(C->getParagraph());
1106 Result << "</Discussion></Parameter>";
1107}
1108
1109void CommentASTToXMLConverter::visitVerbatimBlockComment(
1110 const VerbatimBlockComment *C) {
1111 unsigned NumLines = C->getNumLines();
1112 if (NumLines == 0)
1113 return;
1114
Dmitri Gribenko2aedfbd2013-02-03 17:48:05 +00001115 switch (C->getCommandID()) {
1116 case CommandTraits::KCI_code:
1117 Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">";
1118 break;
1119 default:
1120 Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
1121 break;
1122 }
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001123 for (unsigned i = 0; i != NumLines; ++i) {
1124 appendToResultWithXMLEscaping(C->getText(i));
1125 if (i + 1 != NumLines)
1126 Result << '\n';
1127 }
1128 Result << "</Verbatim>";
1129}
1130
1131void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
1132 const VerbatimBlockLineComment *C) {
1133 llvm_unreachable("should not see this AST node");
1134}
1135
1136void CommentASTToXMLConverter::visitVerbatimLineComment(
1137 const VerbatimLineComment *C) {
Dmitri Gribenko6cffc192012-08-08 22:10:24 +00001138 Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001139 appendToResultWithXMLEscaping(C->getText());
1140 Result << "</Verbatim>";
1141}
1142
1143void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +00001144 FullCommentParts Parts(C, Traits);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001145
1146 const DeclInfo *DI = C->getDeclInfo();
1147 StringRef RootEndTag;
1148 if (DI) {
1149 switch (DI->getKind()) {
1150 case DeclInfo::OtherKind:
1151 RootEndTag = "</Other>";
1152 Result << "<Other";
1153 break;
1154 case DeclInfo::FunctionKind:
1155 RootEndTag = "</Function>";
1156 Result << "<Function";
1157 switch (DI->TemplateKind) {
1158 case DeclInfo::NotTemplate:
1159 break;
1160 case DeclInfo::Template:
1161 Result << " templateKind=\"template\"";
1162 break;
1163 case DeclInfo::TemplateSpecialization:
1164 Result << " templateKind=\"specialization\"";
1165 break;
1166 case DeclInfo::TemplatePartialSpecialization:
1167 llvm_unreachable("partial specializations of functions "
1168 "are not allowed in C++");
1169 }
1170 if (DI->IsInstanceMethod)
1171 Result << " isInstanceMethod=\"1\"";
1172 if (DI->IsClassMethod)
1173 Result << " isClassMethod=\"1\"";
1174 break;
1175 case DeclInfo::ClassKind:
1176 RootEndTag = "</Class>";
1177 Result << "<Class";
1178 switch (DI->TemplateKind) {
1179 case DeclInfo::NotTemplate:
1180 break;
1181 case DeclInfo::Template:
1182 Result << " templateKind=\"template\"";
1183 break;
1184 case DeclInfo::TemplateSpecialization:
1185 Result << " templateKind=\"specialization\"";
1186 break;
1187 case DeclInfo::TemplatePartialSpecialization:
1188 Result << " templateKind=\"partialSpecialization\"";
1189 break;
1190 }
1191 break;
1192 case DeclInfo::VariableKind:
1193 RootEndTag = "</Variable>";
1194 Result << "<Variable";
1195 break;
1196 case DeclInfo::NamespaceKind:
1197 RootEndTag = "</Namespace>";
1198 Result << "<Namespace";
1199 break;
1200 case DeclInfo::TypedefKind:
1201 RootEndTag = "</Typedef>";
1202 Result << "<Typedef";
1203 break;
Dmitri Gribenko168d2342012-08-07 18:59:04 +00001204 case DeclInfo::EnumKind:
1205 RootEndTag = "</Enum>";
1206 Result << "<Enum";
1207 break;
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001208 }
1209
1210 {
1211 // Print line and column number.
Fariborz Jahaniana7d76d22012-10-17 21:58:03 +00001212 SourceLocation Loc = DI->CurrentDecl->getLocation();
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001213 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
1214 FileID FID = LocInfo.first;
1215 unsigned FileOffset = LocInfo.second;
1216
1217 if (!FID.isInvalid()) {
1218 if (const FileEntry *FE = SM.getFileEntryForID(FID)) {
1219 Result << " file=\"";
1220 appendToResultWithXMLEscaping(FE->getName());
1221 Result << "\"";
1222 }
1223 Result << " line=\"" << SM.getLineNumber(FID, FileOffset)
1224 << "\" column=\"" << SM.getColumnNumber(FID, FileOffset)
1225 << "\"";
1226 }
1227 }
1228
1229 // Finish the root tag.
1230 Result << ">";
1231
1232 bool FoundName = false;
Fariborz Jahanian1c883b92012-10-10 18:34:52 +00001233 if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001234 if (DeclarationName DeclName = ND->getDeclName()) {
1235 Result << "<Name>";
1236 std::string Name = DeclName.getAsString();
1237 appendToResultWithXMLEscaping(Name);
1238 FoundName = true;
1239 Result << "</Name>";
1240 }
1241 }
1242 if (!FoundName)
1243 Result << "<Name>&lt;anonymous&gt;</Name>";
1244
1245 {
1246 // Print USR.
1247 SmallString<128> USR;
Fariborz Jahanian1c883b92012-10-10 18:34:52 +00001248 cxcursor::getDeclCursorUSR(DI->CommentDecl, USR);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001249 if (!USR.empty()) {
1250 Result << "<USR>";
1251 appendToResultWithXMLEscaping(USR);
1252 Result << "</USR>";
1253 }
1254 }
1255 } else {
1256 // No DeclInfo -- just emit some root tag and name tag.
1257 RootEndTag = "</Other>";
1258 Result << "<Other><Name>unknown</Name>";
1259 }
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +00001260
1261 if (Parts.Headerfile) {
1262 Result << "<Headerfile>";
1263 visit(Parts.Headerfile);
1264 Result << "</Headerfile>";
1265 }
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001266
Dmitri Gribenko1c1395e2012-10-25 18:28:26 +00001267 {
1268 // Pretty-print the declaration.
1269 Result << "<Declaration>";
1270 SmallString<128> Declaration;
1271 getSourceTextOfDeclaration(DI, Declaration);
Fariborz Jahanianb67908a2012-12-19 00:01:48 +00001272 formatTextOfDeclaration(DI, Declaration);
Dmitri Gribenko1c1395e2012-10-25 18:28:26 +00001273 appendToResultWithXMLEscaping(Declaration);
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +00001274
Dmitri Gribenko1c1395e2012-10-25 18:28:26 +00001275 Result << "</Declaration>";
1276 }
1277
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001278 bool FirstParagraphIsBrief = false;
1279 if (Parts.Brief) {
1280 Result << "<Abstract>";
1281 visit(Parts.Brief);
1282 Result << "</Abstract>";
1283 } else if (Parts.FirstParagraph) {
1284 Result << "<Abstract>";
1285 visit(Parts.FirstParagraph);
1286 Result << "</Abstract>";
1287 FirstParagraphIsBrief = true;
1288 }
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +00001289
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001290 if (Parts.TParams.size() != 0) {
1291 Result << "<TemplateParameters>";
1292 for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
1293 visit(Parts.TParams[i]);
1294 Result << "</TemplateParameters>";
1295 }
1296
1297 if (Parts.Params.size() != 0) {
1298 Result << "<Parameters>";
1299 for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
1300 visit(Parts.Params[i]);
1301 Result << "</Parameters>";
1302 }
1303
Fariborz Jahanianfb6f6f62013-06-21 23:49:29 +00001304 if (Parts.Returns.size() != 0) {
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001305 Result << "<ResultDiscussion>";
Fariborz Jahanianfb6f6f62013-06-21 23:49:29 +00001306 for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
1307 visit(Parts.Returns[i]);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001308 Result << "</ResultDiscussion>";
1309 }
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001310
Fariborz Jahanian1c883b92012-10-10 18:34:52 +00001311 if (DI->CommentDecl->hasAttrs()) {
1312 const AttrVec &Attrs = DI->CommentDecl->getAttrs();
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001313 for (unsigned i = 0, e = Attrs.size(); i != e; i++) {
1314 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
Fariborz Jahaniande0ae1e2012-10-02 20:05:47 +00001315 if (!AA) {
Fariborz Jahaniane61fc442012-10-02 23:01:04 +00001316 if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
1317 if (DA->getMessage().empty())
1318 Result << "<Deprecated/>";
1319 else {
Dmitri Gribenko61b1db12012-10-03 09:04:56 +00001320 Result << "<Deprecated>";
1321 appendToResultWithXMLEscaping(DA->getMessage());
1322 Result << "</Deprecated>";
Fariborz Jahaniane61fc442012-10-02 23:01:04 +00001323 }
1324 }
1325 else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1326 if (UA->getMessage().empty())
1327 Result << "<Unavailable/>";
1328 else {
Dmitri Gribenko61b1db12012-10-03 09:04:56 +00001329 Result << "<Unavailable>";
1330 appendToResultWithXMLEscaping(UA->getMessage());
1331 Result << "</Unavailable>";
Fariborz Jahaniane61fc442012-10-02 23:01:04 +00001332 }
1333 }
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001334 continue;
Fariborz Jahaniande0ae1e2012-10-02 20:05:47 +00001335 }
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001336
1337 // 'availability' attribute.
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001338 Result << "<Availability";
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001339 StringRef Distribution;
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001340 if (AA->getPlatform()) {
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001341 Distribution = AvailabilityAttr::getPrettyPlatformName(
1342 AA->getPlatform()->getName());
1343 if (Distribution.empty())
1344 Distribution = AA->getPlatform()->getName();
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001345 }
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001346 Result << " distribution=\"" << Distribution << "\">";
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001347 VersionTuple IntroducedInVersion = AA->getIntroduced();
1348 if (!IntroducedInVersion.empty()) {
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001349 Result << "<IntroducedInVersion>"
1350 << IntroducedInVersion.getAsString()
1351 << "</IntroducedInVersion>";
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001352 }
1353 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1354 if (!DeprecatedInVersion.empty()) {
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001355 Result << "<DeprecatedInVersion>"
1356 << DeprecatedInVersion.getAsString()
1357 << "</DeprecatedInVersion>";
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001358 }
1359 VersionTuple RemovedAfterVersion = AA->getObsoleted();
1360 if (!RemovedAfterVersion.empty()) {
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001361 Result << "<RemovedAfterVersion>"
1362 << RemovedAfterVersion.getAsString()
1363 << "</RemovedAfterVersion>";
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001364 }
1365 StringRef DeprecationSummary = AA->getMessage();
1366 if (!DeprecationSummary.empty()) {
Dmitri Gribenko61b1db12012-10-03 09:04:56 +00001367 Result << "<DeprecationSummary>";
1368 appendToResultWithXMLEscaping(DeprecationSummary);
1369 Result << "</DeprecationSummary>";
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001370 }
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001371 if (AA->getUnavailable())
Fariborz Jahaniane61fc442012-10-02 23:01:04 +00001372 Result << "<Unavailable/>";
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001373 Result << "</Availability>";
Fariborz Jahanian35760a82012-09-28 22:35:49 +00001374 }
1375 }
Fariborz Jahanianc491c3f2012-10-01 18:42:25 +00001376
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001377 {
1378 bool StartTagEmitted = false;
1379 for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1380 const Comment *C = Parts.MiscBlocks[i];
1381 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1382 continue;
1383 if (!StartTagEmitted) {
1384 Result << "<Discussion>";
1385 StartTagEmitted = true;
1386 }
1387 visit(C);
1388 }
1389 if (StartTagEmitted)
1390 Result << "</Discussion>";
1391 }
1392
1393 Result << RootEndTag;
1394
1395 Result.flush();
1396}
1397
1398void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1399 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
1400 const char C = *I;
1401 switch (C) {
1402 case '&':
1403 Result << "&amp;";
1404 break;
1405 case '<':
1406 Result << "&lt;";
1407 break;
1408 case '>':
1409 Result << "&gt;";
1410 break;
1411 case '"':
1412 Result << "&quot;";
1413 break;
1414 case '\'':
1415 Result << "&apos;";
1416 break;
1417 default:
1418 Result << C;
1419 break;
1420 }
1421 }
1422}
1423
1424extern "C" {
1425
Dmitri Gribenko7acbf002012-09-10 20:32:42 +00001426CXString clang_FullComment_getAsXML(CXComment CXC) {
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001427 const FullComment *FC = getASTNodeAs<FullComment>(CXC);
1428 if (!FC)
Dmitri Gribenkof98dfba2013-02-01 14:13:32 +00001429 return cxstring::createNull();
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +00001430 ASTContext &Context = FC->getDeclInfo()->CurrentDecl->getASTContext();
Dmitri Gribenko7acbf002012-09-10 20:32:42 +00001431 CXTranslationUnit TU = CXC.TranslationUnit;
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +00001432 SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
Dmitri Gribenkoba82fea2013-01-26 21:39:50 +00001433
1434 if (!TU->FormatContext) {
1435 TU->FormatContext = new SimpleFormatContext(Context.getLangOpts());
Fariborz Jahanianbbdb9f22012-12-19 00:35:23 +00001436 } else if ((TU->FormatInMemoryUniqueId % 1000) == 0) {
Fariborz Jahanianb67908a2012-12-19 00:01:48 +00001437 // Delete after some number of iterators, so the buffers don't grow
1438 // too large.
Dmitri Gribenkoba82fea2013-01-26 21:39:50 +00001439 delete TU->FormatContext;
1440 TU->FormatContext = new SimpleFormatContext(Context.getLangOpts());
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +00001441 }
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001442
1443 SmallString<1024> XML;
Fariborz Jahanian9b7ab872012-12-18 23:02:59 +00001444 CommentASTToXMLConverter Converter(FC, XML, getCommandTraits(CXC), SM,
Dmitri Gribenkoba82fea2013-01-26 21:39:50 +00001445 *TU->FormatContext,
1446 TU->FormatInMemoryUniqueId++);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001447 Converter.visit(FC);
Dmitri Gribenko2f23e9c2013-02-02 02:19:29 +00001448 return cxstring::createDup(XML.str());
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001449}
1450
1451} // end extern "C"
1452