xref: /minix3/external/bsd/llvm/dist/clang/lib/Index/CommentToXML.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //===--- CommentToXML.cpp - Convert comments to XML representation --------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc 
10f4a2713aSLionel Sambuc #include "clang/Index/CommentToXML.h"
11f4a2713aSLionel Sambuc #include "SimpleFormatContext.h"
12f4a2713aSLionel Sambuc #include "clang/AST/ASTContext.h"
13*0a6a1f1dSLionel Sambuc #include "clang/AST/Attr.h"
14f4a2713aSLionel Sambuc #include "clang/AST/Comment.h"
15f4a2713aSLionel Sambuc #include "clang/AST/CommentVisitor.h"
16f4a2713aSLionel Sambuc #include "clang/Format/Format.h"
17f4a2713aSLionel Sambuc #include "clang/Index/USRGeneration.h"
18f4a2713aSLionel Sambuc #include "llvm/ADT/StringExtras.h"
19f4a2713aSLionel Sambuc #include "llvm/ADT/TinyPtrVector.h"
20f4a2713aSLionel Sambuc #include "llvm/Support/raw_ostream.h"
21f4a2713aSLionel Sambuc 
22f4a2713aSLionel Sambuc using namespace clang;
23f4a2713aSLionel Sambuc using namespace clang::comments;
24f4a2713aSLionel Sambuc using namespace clang::index;
25f4a2713aSLionel Sambuc 
26f4a2713aSLionel Sambuc namespace {
27f4a2713aSLionel Sambuc 
28f4a2713aSLionel Sambuc /// This comparison will sort parameters with valid index by index, then vararg
29f4a2713aSLionel Sambuc /// parameters, and invalid (unresolved) parameters last.
30f4a2713aSLionel Sambuc class ParamCommandCommentCompareIndex {
31f4a2713aSLionel Sambuc public:
operator ()(const ParamCommandComment * LHS,const ParamCommandComment * RHS) const32f4a2713aSLionel Sambuc   bool operator()(const ParamCommandComment *LHS,
33f4a2713aSLionel Sambuc                   const ParamCommandComment *RHS) const {
34f4a2713aSLionel Sambuc     unsigned LHSIndex = UINT_MAX;
35f4a2713aSLionel Sambuc     unsigned RHSIndex = UINT_MAX;
36f4a2713aSLionel Sambuc 
37f4a2713aSLionel Sambuc     if (LHS->isParamIndexValid()) {
38f4a2713aSLionel Sambuc       if (LHS->isVarArgParam())
39f4a2713aSLionel Sambuc         LHSIndex = UINT_MAX - 1;
40f4a2713aSLionel Sambuc       else
41f4a2713aSLionel Sambuc         LHSIndex = LHS->getParamIndex();
42f4a2713aSLionel Sambuc     }
43f4a2713aSLionel Sambuc     if (RHS->isParamIndexValid()) {
44f4a2713aSLionel Sambuc       if (RHS->isVarArgParam())
45f4a2713aSLionel Sambuc         RHSIndex = UINT_MAX - 1;
46f4a2713aSLionel Sambuc       else
47f4a2713aSLionel Sambuc         RHSIndex = RHS->getParamIndex();
48f4a2713aSLionel Sambuc     }
49f4a2713aSLionel Sambuc     return LHSIndex < RHSIndex;
50f4a2713aSLionel Sambuc   }
51f4a2713aSLionel Sambuc };
52f4a2713aSLionel Sambuc 
53f4a2713aSLionel Sambuc /// This comparison will sort template parameters in the following order:
54f4a2713aSLionel Sambuc /// \li real template parameters (depth = 1) in index order;
55f4a2713aSLionel Sambuc /// \li all other names (depth > 1);
56f4a2713aSLionel Sambuc /// \li unresolved names.
57f4a2713aSLionel Sambuc class TParamCommandCommentComparePosition {
58f4a2713aSLionel Sambuc public:
operator ()(const TParamCommandComment * LHS,const TParamCommandComment * RHS) const59f4a2713aSLionel Sambuc   bool operator()(const TParamCommandComment *LHS,
60f4a2713aSLionel Sambuc                   const TParamCommandComment *RHS) const {
61f4a2713aSLionel Sambuc     // Sort unresolved names last.
62f4a2713aSLionel Sambuc     if (!LHS->isPositionValid())
63f4a2713aSLionel Sambuc       return false;
64f4a2713aSLionel Sambuc     if (!RHS->isPositionValid())
65f4a2713aSLionel Sambuc       return true;
66f4a2713aSLionel Sambuc 
67f4a2713aSLionel Sambuc     if (LHS->getDepth() > 1)
68f4a2713aSLionel Sambuc       return false;
69f4a2713aSLionel Sambuc     if (RHS->getDepth() > 1)
70f4a2713aSLionel Sambuc       return true;
71f4a2713aSLionel Sambuc 
72f4a2713aSLionel Sambuc     // Sort template parameters in index order.
73f4a2713aSLionel Sambuc     if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
74f4a2713aSLionel Sambuc       return LHS->getIndex(0) < RHS->getIndex(0);
75f4a2713aSLionel Sambuc 
76f4a2713aSLionel Sambuc     // Leave all other names in source order.
77f4a2713aSLionel Sambuc     return true;
78f4a2713aSLionel Sambuc   }
79f4a2713aSLionel Sambuc };
80f4a2713aSLionel Sambuc 
81f4a2713aSLionel Sambuc /// Separate parts of a FullComment.
82f4a2713aSLionel Sambuc struct FullCommentParts {
83f4a2713aSLionel Sambuc   /// Take a full comment apart and initialize members accordingly.
84f4a2713aSLionel Sambuc   FullCommentParts(const FullComment *C,
85f4a2713aSLionel Sambuc                    const CommandTraits &Traits);
86f4a2713aSLionel Sambuc 
87f4a2713aSLionel Sambuc   const BlockContentComment *Brief;
88f4a2713aSLionel Sambuc   const BlockContentComment *Headerfile;
89f4a2713aSLionel Sambuc   const ParagraphComment *FirstParagraph;
90f4a2713aSLionel Sambuc   SmallVector<const BlockCommandComment *, 4> Returns;
91f4a2713aSLionel Sambuc   SmallVector<const ParamCommandComment *, 8> Params;
92f4a2713aSLionel Sambuc   SmallVector<const TParamCommandComment *, 4> TParams;
93f4a2713aSLionel Sambuc   llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
94f4a2713aSLionel Sambuc   SmallVector<const BlockContentComment *, 8> MiscBlocks;
95f4a2713aSLionel Sambuc };
96f4a2713aSLionel Sambuc 
FullCommentParts(const FullComment * C,const CommandTraits & Traits)97f4a2713aSLionel Sambuc FullCommentParts::FullCommentParts(const FullComment *C,
98f4a2713aSLionel Sambuc                                    const CommandTraits &Traits) :
99*0a6a1f1dSLionel Sambuc     Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
100f4a2713aSLionel Sambuc   for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
101f4a2713aSLionel Sambuc        I != E; ++I) {
102f4a2713aSLionel Sambuc     const Comment *Child = *I;
103f4a2713aSLionel Sambuc     if (!Child)
104f4a2713aSLionel Sambuc       continue;
105f4a2713aSLionel Sambuc     switch (Child->getCommentKind()) {
106f4a2713aSLionel Sambuc     case Comment::NoCommentKind:
107f4a2713aSLionel Sambuc       continue;
108f4a2713aSLionel Sambuc 
109f4a2713aSLionel Sambuc     case Comment::ParagraphCommentKind: {
110f4a2713aSLionel Sambuc       const ParagraphComment *PC = cast<ParagraphComment>(Child);
111f4a2713aSLionel Sambuc       if (PC->isWhitespace())
112f4a2713aSLionel Sambuc         break;
113f4a2713aSLionel Sambuc       if (!FirstParagraph)
114f4a2713aSLionel Sambuc         FirstParagraph = PC;
115f4a2713aSLionel Sambuc 
116f4a2713aSLionel Sambuc       MiscBlocks.push_back(PC);
117f4a2713aSLionel Sambuc       break;
118f4a2713aSLionel Sambuc     }
119f4a2713aSLionel Sambuc 
120f4a2713aSLionel Sambuc     case Comment::BlockCommandCommentKind: {
121f4a2713aSLionel Sambuc       const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
122f4a2713aSLionel Sambuc       const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
123f4a2713aSLionel Sambuc       if (!Brief && Info->IsBriefCommand) {
124f4a2713aSLionel Sambuc         Brief = BCC;
125f4a2713aSLionel Sambuc         break;
126f4a2713aSLionel Sambuc       }
127f4a2713aSLionel Sambuc       if (!Headerfile && Info->IsHeaderfileCommand) {
128f4a2713aSLionel Sambuc         Headerfile = BCC;
129f4a2713aSLionel Sambuc         break;
130f4a2713aSLionel Sambuc       }
131f4a2713aSLionel Sambuc       if (Info->IsReturnsCommand) {
132f4a2713aSLionel Sambuc         Returns.push_back(BCC);
133f4a2713aSLionel Sambuc         break;
134f4a2713aSLionel Sambuc       }
135f4a2713aSLionel Sambuc       if (Info->IsThrowsCommand) {
136f4a2713aSLionel Sambuc         Exceptions.push_back(BCC);
137f4a2713aSLionel Sambuc         break;
138f4a2713aSLionel Sambuc       }
139f4a2713aSLionel Sambuc       MiscBlocks.push_back(BCC);
140f4a2713aSLionel Sambuc       break;
141f4a2713aSLionel Sambuc     }
142f4a2713aSLionel Sambuc 
143f4a2713aSLionel Sambuc     case Comment::ParamCommandCommentKind: {
144f4a2713aSLionel Sambuc       const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
145f4a2713aSLionel Sambuc       if (!PCC->hasParamName())
146f4a2713aSLionel Sambuc         break;
147f4a2713aSLionel Sambuc 
148f4a2713aSLionel Sambuc       if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
149f4a2713aSLionel Sambuc         break;
150f4a2713aSLionel Sambuc 
151f4a2713aSLionel Sambuc       Params.push_back(PCC);
152f4a2713aSLionel Sambuc       break;
153f4a2713aSLionel Sambuc     }
154f4a2713aSLionel Sambuc 
155f4a2713aSLionel Sambuc     case Comment::TParamCommandCommentKind: {
156f4a2713aSLionel Sambuc       const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
157f4a2713aSLionel Sambuc       if (!TPCC->hasParamName())
158f4a2713aSLionel Sambuc         break;
159f4a2713aSLionel Sambuc 
160f4a2713aSLionel Sambuc       if (!TPCC->hasNonWhitespaceParagraph())
161f4a2713aSLionel Sambuc         break;
162f4a2713aSLionel Sambuc 
163f4a2713aSLionel Sambuc       TParams.push_back(TPCC);
164f4a2713aSLionel Sambuc       break;
165f4a2713aSLionel Sambuc     }
166f4a2713aSLionel Sambuc 
167f4a2713aSLionel Sambuc     case Comment::VerbatimBlockCommentKind:
168f4a2713aSLionel Sambuc       MiscBlocks.push_back(cast<BlockCommandComment>(Child));
169f4a2713aSLionel Sambuc       break;
170f4a2713aSLionel Sambuc 
171f4a2713aSLionel Sambuc     case Comment::VerbatimLineCommentKind: {
172f4a2713aSLionel Sambuc       const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
173f4a2713aSLionel Sambuc       const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
174f4a2713aSLionel Sambuc       if (!Info->IsDeclarationCommand)
175f4a2713aSLionel Sambuc         MiscBlocks.push_back(VLC);
176f4a2713aSLionel Sambuc       break;
177f4a2713aSLionel Sambuc     }
178f4a2713aSLionel Sambuc 
179f4a2713aSLionel Sambuc     case Comment::TextCommentKind:
180f4a2713aSLionel Sambuc     case Comment::InlineCommandCommentKind:
181f4a2713aSLionel Sambuc     case Comment::HTMLStartTagCommentKind:
182f4a2713aSLionel Sambuc     case Comment::HTMLEndTagCommentKind:
183f4a2713aSLionel Sambuc     case Comment::VerbatimBlockLineCommentKind:
184f4a2713aSLionel Sambuc     case Comment::FullCommentKind:
185f4a2713aSLionel Sambuc       llvm_unreachable("AST node of this kind can't be a child of "
186f4a2713aSLionel Sambuc                        "a FullComment");
187f4a2713aSLionel Sambuc     }
188f4a2713aSLionel Sambuc   }
189f4a2713aSLionel Sambuc 
190f4a2713aSLionel Sambuc   // Sort params in order they are declared in the function prototype.
191f4a2713aSLionel Sambuc   // Unresolved parameters are put at the end of the list in the same order
192f4a2713aSLionel Sambuc   // they were seen in the comment.
193f4a2713aSLionel Sambuc   std::stable_sort(Params.begin(), Params.end(),
194f4a2713aSLionel Sambuc                    ParamCommandCommentCompareIndex());
195f4a2713aSLionel Sambuc 
196f4a2713aSLionel Sambuc   std::stable_sort(TParams.begin(), TParams.end(),
197f4a2713aSLionel Sambuc                    TParamCommandCommentComparePosition());
198f4a2713aSLionel Sambuc }
199f4a2713aSLionel Sambuc 
printHTMLStartTagComment(const HTMLStartTagComment * C,llvm::raw_svector_ostream & Result)200f4a2713aSLionel Sambuc void printHTMLStartTagComment(const HTMLStartTagComment *C,
201f4a2713aSLionel Sambuc                               llvm::raw_svector_ostream &Result) {
202f4a2713aSLionel Sambuc   Result << "<" << C->getTagName();
203f4a2713aSLionel Sambuc 
204f4a2713aSLionel Sambuc   if (C->getNumAttrs() != 0) {
205f4a2713aSLionel Sambuc     for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
206f4a2713aSLionel Sambuc       Result << " ";
207f4a2713aSLionel Sambuc       const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
208f4a2713aSLionel Sambuc       Result << Attr.Name;
209f4a2713aSLionel Sambuc       if (!Attr.Value.empty())
210f4a2713aSLionel Sambuc         Result << "=\"" << Attr.Value << "\"";
211f4a2713aSLionel Sambuc     }
212f4a2713aSLionel Sambuc   }
213f4a2713aSLionel Sambuc 
214f4a2713aSLionel Sambuc   if (!C->isSelfClosing())
215f4a2713aSLionel Sambuc     Result << ">";
216f4a2713aSLionel Sambuc   else
217f4a2713aSLionel Sambuc     Result << "/>";
218f4a2713aSLionel Sambuc }
219f4a2713aSLionel Sambuc 
220f4a2713aSLionel Sambuc class CommentASTToHTMLConverter :
221f4a2713aSLionel Sambuc     public ConstCommentVisitor<CommentASTToHTMLConverter> {
222f4a2713aSLionel Sambuc public:
223f4a2713aSLionel Sambuc   /// \param Str accumulator for HTML.
CommentASTToHTMLConverter(const FullComment * FC,SmallVectorImpl<char> & Str,const CommandTraits & Traits)224f4a2713aSLionel Sambuc   CommentASTToHTMLConverter(const FullComment *FC,
225f4a2713aSLionel Sambuc                             SmallVectorImpl<char> &Str,
226f4a2713aSLionel Sambuc                             const CommandTraits &Traits) :
227f4a2713aSLionel Sambuc       FC(FC), Result(Str), Traits(Traits)
228f4a2713aSLionel Sambuc   { }
229f4a2713aSLionel Sambuc 
230f4a2713aSLionel Sambuc   // Inline content.
231f4a2713aSLionel Sambuc   void visitTextComment(const TextComment *C);
232f4a2713aSLionel Sambuc   void visitInlineCommandComment(const InlineCommandComment *C);
233f4a2713aSLionel Sambuc   void visitHTMLStartTagComment(const HTMLStartTagComment *C);
234f4a2713aSLionel Sambuc   void visitHTMLEndTagComment(const HTMLEndTagComment *C);
235f4a2713aSLionel Sambuc 
236f4a2713aSLionel Sambuc   // Block content.
237f4a2713aSLionel Sambuc   void visitParagraphComment(const ParagraphComment *C);
238f4a2713aSLionel Sambuc   void visitBlockCommandComment(const BlockCommandComment *C);
239f4a2713aSLionel Sambuc   void visitParamCommandComment(const ParamCommandComment *C);
240f4a2713aSLionel Sambuc   void visitTParamCommandComment(const TParamCommandComment *C);
241f4a2713aSLionel Sambuc   void visitVerbatimBlockComment(const VerbatimBlockComment *C);
242f4a2713aSLionel Sambuc   void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
243f4a2713aSLionel Sambuc   void visitVerbatimLineComment(const VerbatimLineComment *C);
244f4a2713aSLionel Sambuc 
245f4a2713aSLionel Sambuc   void visitFullComment(const FullComment *C);
246f4a2713aSLionel Sambuc 
247f4a2713aSLionel Sambuc   // Helpers.
248f4a2713aSLionel Sambuc 
249f4a2713aSLionel Sambuc   /// Convert a paragraph that is not a block by itself (an argument to some
250f4a2713aSLionel Sambuc   /// command).
251f4a2713aSLionel Sambuc   void visitNonStandaloneParagraphComment(const ParagraphComment *C);
252f4a2713aSLionel Sambuc 
253f4a2713aSLionel Sambuc   void appendToResultWithHTMLEscaping(StringRef S);
254f4a2713aSLionel Sambuc 
255f4a2713aSLionel Sambuc private:
256f4a2713aSLionel Sambuc   const FullComment *FC;
257f4a2713aSLionel Sambuc   /// Output stream for HTML.
258f4a2713aSLionel Sambuc   llvm::raw_svector_ostream Result;
259f4a2713aSLionel Sambuc 
260f4a2713aSLionel Sambuc   const CommandTraits &Traits;
261f4a2713aSLionel Sambuc };
262f4a2713aSLionel Sambuc } // end unnamed namespace
263f4a2713aSLionel Sambuc 
visitTextComment(const TextComment * C)264f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
265f4a2713aSLionel Sambuc   appendToResultWithHTMLEscaping(C->getText());
266f4a2713aSLionel Sambuc }
267f4a2713aSLionel Sambuc 
visitInlineCommandComment(const InlineCommandComment * C)268f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitInlineCommandComment(
269f4a2713aSLionel Sambuc                                   const InlineCommandComment *C) {
270f4a2713aSLionel Sambuc   // Nothing to render if no arguments supplied.
271f4a2713aSLionel Sambuc   if (C->getNumArgs() == 0)
272f4a2713aSLionel Sambuc     return;
273f4a2713aSLionel Sambuc 
274f4a2713aSLionel Sambuc   // Nothing to render if argument is empty.
275f4a2713aSLionel Sambuc   StringRef Arg0 = C->getArgText(0);
276f4a2713aSLionel Sambuc   if (Arg0.empty())
277f4a2713aSLionel Sambuc     return;
278f4a2713aSLionel Sambuc 
279f4a2713aSLionel Sambuc   switch (C->getRenderKind()) {
280f4a2713aSLionel Sambuc   case InlineCommandComment::RenderNormal:
281f4a2713aSLionel Sambuc     for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
282f4a2713aSLionel Sambuc       appendToResultWithHTMLEscaping(C->getArgText(i));
283f4a2713aSLionel Sambuc       Result << " ";
284f4a2713aSLionel Sambuc     }
285f4a2713aSLionel Sambuc     return;
286f4a2713aSLionel Sambuc 
287f4a2713aSLionel Sambuc   case InlineCommandComment::RenderBold:
288f4a2713aSLionel Sambuc     assert(C->getNumArgs() == 1);
289f4a2713aSLionel Sambuc     Result << "<b>";
290f4a2713aSLionel Sambuc     appendToResultWithHTMLEscaping(Arg0);
291f4a2713aSLionel Sambuc     Result << "</b>";
292f4a2713aSLionel Sambuc     return;
293f4a2713aSLionel Sambuc   case InlineCommandComment::RenderMonospaced:
294f4a2713aSLionel Sambuc     assert(C->getNumArgs() == 1);
295f4a2713aSLionel Sambuc     Result << "<tt>";
296f4a2713aSLionel Sambuc     appendToResultWithHTMLEscaping(Arg0);
297f4a2713aSLionel Sambuc     Result<< "</tt>";
298f4a2713aSLionel Sambuc     return;
299f4a2713aSLionel Sambuc   case InlineCommandComment::RenderEmphasized:
300f4a2713aSLionel Sambuc     assert(C->getNumArgs() == 1);
301f4a2713aSLionel Sambuc     Result << "<em>";
302f4a2713aSLionel Sambuc     appendToResultWithHTMLEscaping(Arg0);
303f4a2713aSLionel Sambuc     Result << "</em>";
304f4a2713aSLionel Sambuc     return;
305f4a2713aSLionel Sambuc   }
306f4a2713aSLionel Sambuc }
307f4a2713aSLionel Sambuc 
visitHTMLStartTagComment(const HTMLStartTagComment * C)308f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitHTMLStartTagComment(
309f4a2713aSLionel Sambuc                                   const HTMLStartTagComment *C) {
310f4a2713aSLionel Sambuc   printHTMLStartTagComment(C, Result);
311f4a2713aSLionel Sambuc }
312f4a2713aSLionel Sambuc 
visitHTMLEndTagComment(const HTMLEndTagComment * C)313f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitHTMLEndTagComment(
314f4a2713aSLionel Sambuc                                   const HTMLEndTagComment *C) {
315f4a2713aSLionel Sambuc   Result << "</" << C->getTagName() << ">";
316f4a2713aSLionel Sambuc }
317f4a2713aSLionel Sambuc 
visitParagraphComment(const ParagraphComment * C)318f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitParagraphComment(
319f4a2713aSLionel Sambuc                                   const ParagraphComment *C) {
320f4a2713aSLionel Sambuc   if (C->isWhitespace())
321f4a2713aSLionel Sambuc     return;
322f4a2713aSLionel Sambuc 
323f4a2713aSLionel Sambuc   Result << "<p>";
324f4a2713aSLionel Sambuc   for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
325f4a2713aSLionel Sambuc        I != E; ++I) {
326f4a2713aSLionel Sambuc     visit(*I);
327f4a2713aSLionel Sambuc   }
328f4a2713aSLionel Sambuc   Result << "</p>";
329f4a2713aSLionel Sambuc }
330f4a2713aSLionel Sambuc 
visitBlockCommandComment(const BlockCommandComment * C)331f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitBlockCommandComment(
332f4a2713aSLionel Sambuc                                   const BlockCommandComment *C) {
333f4a2713aSLionel Sambuc   const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
334f4a2713aSLionel Sambuc   if (Info->IsBriefCommand) {
335f4a2713aSLionel Sambuc     Result << "<p class=\"para-brief\">";
336f4a2713aSLionel Sambuc     visitNonStandaloneParagraphComment(C->getParagraph());
337f4a2713aSLionel Sambuc     Result << "</p>";
338f4a2713aSLionel Sambuc     return;
339f4a2713aSLionel Sambuc   }
340f4a2713aSLionel Sambuc   if (Info->IsReturnsCommand) {
341f4a2713aSLionel Sambuc     Result << "<p class=\"para-returns\">"
342f4a2713aSLionel Sambuc               "<span class=\"word-returns\">Returns</span> ";
343f4a2713aSLionel Sambuc     visitNonStandaloneParagraphComment(C->getParagraph());
344f4a2713aSLionel Sambuc     Result << "</p>";
345f4a2713aSLionel Sambuc     return;
346f4a2713aSLionel Sambuc   }
347f4a2713aSLionel Sambuc   // We don't know anything about this command.  Just render the paragraph.
348f4a2713aSLionel Sambuc   visit(C->getParagraph());
349f4a2713aSLionel Sambuc }
350f4a2713aSLionel Sambuc 
visitParamCommandComment(const ParamCommandComment * C)351f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitParamCommandComment(
352f4a2713aSLionel Sambuc                                   const ParamCommandComment *C) {
353f4a2713aSLionel Sambuc   if (C->isParamIndexValid()) {
354f4a2713aSLionel Sambuc     if (C->isVarArgParam()) {
355f4a2713aSLionel Sambuc       Result << "<dt class=\"param-name-index-vararg\">";
356f4a2713aSLionel Sambuc       appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
357f4a2713aSLionel Sambuc     } else {
358f4a2713aSLionel Sambuc       Result << "<dt class=\"param-name-index-"
359f4a2713aSLionel Sambuc              << C->getParamIndex()
360f4a2713aSLionel Sambuc              << "\">";
361f4a2713aSLionel Sambuc       appendToResultWithHTMLEscaping(C->getParamName(FC));
362f4a2713aSLionel Sambuc     }
363f4a2713aSLionel Sambuc   } else {
364f4a2713aSLionel Sambuc     Result << "<dt class=\"param-name-index-invalid\">";
365f4a2713aSLionel Sambuc     appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
366f4a2713aSLionel Sambuc   }
367f4a2713aSLionel Sambuc   Result << "</dt>";
368f4a2713aSLionel Sambuc 
369f4a2713aSLionel Sambuc   if (C->isParamIndexValid()) {
370f4a2713aSLionel Sambuc     if (C->isVarArgParam())
371f4a2713aSLionel Sambuc       Result << "<dd class=\"param-descr-index-vararg\">";
372f4a2713aSLionel Sambuc     else
373f4a2713aSLionel Sambuc       Result << "<dd class=\"param-descr-index-"
374f4a2713aSLionel Sambuc              << C->getParamIndex()
375f4a2713aSLionel Sambuc              << "\">";
376f4a2713aSLionel Sambuc   } else
377f4a2713aSLionel Sambuc     Result << "<dd class=\"param-descr-index-invalid\">";
378f4a2713aSLionel Sambuc 
379f4a2713aSLionel Sambuc   visitNonStandaloneParagraphComment(C->getParagraph());
380f4a2713aSLionel Sambuc   Result << "</dd>";
381f4a2713aSLionel Sambuc }
382f4a2713aSLionel Sambuc 
visitTParamCommandComment(const TParamCommandComment * C)383f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitTParamCommandComment(
384f4a2713aSLionel Sambuc                                   const TParamCommandComment *C) {
385f4a2713aSLionel Sambuc   if (C->isPositionValid()) {
386f4a2713aSLionel Sambuc     if (C->getDepth() == 1)
387f4a2713aSLionel Sambuc       Result << "<dt class=\"tparam-name-index-"
388f4a2713aSLionel Sambuc              << C->getIndex(0)
389f4a2713aSLionel Sambuc              << "\">";
390f4a2713aSLionel Sambuc     else
391f4a2713aSLionel Sambuc       Result << "<dt class=\"tparam-name-index-other\">";
392f4a2713aSLionel Sambuc     appendToResultWithHTMLEscaping(C->getParamName(FC));
393f4a2713aSLionel Sambuc   } else {
394f4a2713aSLionel Sambuc     Result << "<dt class=\"tparam-name-index-invalid\">";
395f4a2713aSLionel Sambuc     appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
396f4a2713aSLionel Sambuc   }
397f4a2713aSLionel Sambuc 
398f4a2713aSLionel Sambuc   Result << "</dt>";
399f4a2713aSLionel Sambuc 
400f4a2713aSLionel Sambuc   if (C->isPositionValid()) {
401f4a2713aSLionel Sambuc     if (C->getDepth() == 1)
402f4a2713aSLionel Sambuc       Result << "<dd class=\"tparam-descr-index-"
403f4a2713aSLionel Sambuc              << C->getIndex(0)
404f4a2713aSLionel Sambuc              << "\">";
405f4a2713aSLionel Sambuc     else
406f4a2713aSLionel Sambuc       Result << "<dd class=\"tparam-descr-index-other\">";
407f4a2713aSLionel Sambuc   } else
408f4a2713aSLionel Sambuc     Result << "<dd class=\"tparam-descr-index-invalid\">";
409f4a2713aSLionel Sambuc 
410f4a2713aSLionel Sambuc   visitNonStandaloneParagraphComment(C->getParagraph());
411f4a2713aSLionel Sambuc   Result << "</dd>";
412f4a2713aSLionel Sambuc }
413f4a2713aSLionel Sambuc 
visitVerbatimBlockComment(const VerbatimBlockComment * C)414f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitVerbatimBlockComment(
415f4a2713aSLionel Sambuc                                   const VerbatimBlockComment *C) {
416f4a2713aSLionel Sambuc   unsigned NumLines = C->getNumLines();
417f4a2713aSLionel Sambuc   if (NumLines == 0)
418f4a2713aSLionel Sambuc     return;
419f4a2713aSLionel Sambuc 
420f4a2713aSLionel Sambuc   Result << "<pre>";
421f4a2713aSLionel Sambuc   for (unsigned i = 0; i != NumLines; ++i) {
422f4a2713aSLionel Sambuc     appendToResultWithHTMLEscaping(C->getText(i));
423f4a2713aSLionel Sambuc     if (i + 1 != NumLines)
424f4a2713aSLionel Sambuc       Result << '\n';
425f4a2713aSLionel Sambuc   }
426f4a2713aSLionel Sambuc   Result << "</pre>";
427f4a2713aSLionel Sambuc }
428f4a2713aSLionel Sambuc 
visitVerbatimBlockLineComment(const VerbatimBlockLineComment * C)429f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
430f4a2713aSLionel Sambuc                                   const VerbatimBlockLineComment *C) {
431f4a2713aSLionel Sambuc   llvm_unreachable("should not see this AST node");
432f4a2713aSLionel Sambuc }
433f4a2713aSLionel Sambuc 
visitVerbatimLineComment(const VerbatimLineComment * C)434f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitVerbatimLineComment(
435f4a2713aSLionel Sambuc                                   const VerbatimLineComment *C) {
436f4a2713aSLionel Sambuc   Result << "<pre>";
437f4a2713aSLionel Sambuc   appendToResultWithHTMLEscaping(C->getText());
438f4a2713aSLionel Sambuc   Result << "</pre>";
439f4a2713aSLionel Sambuc }
440f4a2713aSLionel Sambuc 
visitFullComment(const FullComment * C)441f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
442f4a2713aSLionel Sambuc   FullCommentParts Parts(C, Traits);
443f4a2713aSLionel Sambuc 
444f4a2713aSLionel Sambuc   bool FirstParagraphIsBrief = false;
445f4a2713aSLionel Sambuc   if (Parts.Headerfile)
446f4a2713aSLionel Sambuc     visit(Parts.Headerfile);
447f4a2713aSLionel Sambuc   if (Parts.Brief)
448f4a2713aSLionel Sambuc     visit(Parts.Brief);
449f4a2713aSLionel Sambuc   else if (Parts.FirstParagraph) {
450f4a2713aSLionel Sambuc     Result << "<p class=\"para-brief\">";
451f4a2713aSLionel Sambuc     visitNonStandaloneParagraphComment(Parts.FirstParagraph);
452f4a2713aSLionel Sambuc     Result << "</p>";
453f4a2713aSLionel Sambuc     FirstParagraphIsBrief = true;
454f4a2713aSLionel Sambuc   }
455f4a2713aSLionel Sambuc 
456f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
457f4a2713aSLionel Sambuc     const Comment *C = Parts.MiscBlocks[i];
458f4a2713aSLionel Sambuc     if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
459f4a2713aSLionel Sambuc       continue;
460f4a2713aSLionel Sambuc     visit(C);
461f4a2713aSLionel Sambuc   }
462f4a2713aSLionel Sambuc 
463f4a2713aSLionel Sambuc   if (Parts.TParams.size() != 0) {
464f4a2713aSLionel Sambuc     Result << "<dl>";
465f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
466f4a2713aSLionel Sambuc       visit(Parts.TParams[i]);
467f4a2713aSLionel Sambuc     Result << "</dl>";
468f4a2713aSLionel Sambuc   }
469f4a2713aSLionel Sambuc 
470f4a2713aSLionel Sambuc   if (Parts.Params.size() != 0) {
471f4a2713aSLionel Sambuc     Result << "<dl>";
472f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
473f4a2713aSLionel Sambuc       visit(Parts.Params[i]);
474f4a2713aSLionel Sambuc     Result << "</dl>";
475f4a2713aSLionel Sambuc   }
476f4a2713aSLionel Sambuc 
477f4a2713aSLionel Sambuc   if (Parts.Returns.size() != 0) {
478f4a2713aSLionel Sambuc     Result << "<div class=\"result-discussion\">";
479f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
480f4a2713aSLionel Sambuc       visit(Parts.Returns[i]);
481f4a2713aSLionel Sambuc     Result << "</div>";
482f4a2713aSLionel Sambuc   }
483f4a2713aSLionel Sambuc 
484f4a2713aSLionel Sambuc   Result.flush();
485f4a2713aSLionel Sambuc }
486f4a2713aSLionel Sambuc 
visitNonStandaloneParagraphComment(const ParagraphComment * C)487f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
488f4a2713aSLionel Sambuc                                   const ParagraphComment *C) {
489f4a2713aSLionel Sambuc   if (!C)
490f4a2713aSLionel Sambuc     return;
491f4a2713aSLionel Sambuc 
492f4a2713aSLionel Sambuc   for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
493f4a2713aSLionel Sambuc        I != E; ++I) {
494f4a2713aSLionel Sambuc     visit(*I);
495f4a2713aSLionel Sambuc   }
496f4a2713aSLionel Sambuc }
497f4a2713aSLionel Sambuc 
appendToResultWithHTMLEscaping(StringRef S)498f4a2713aSLionel Sambuc void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
499f4a2713aSLionel Sambuc   for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
500f4a2713aSLionel Sambuc     const char C = *I;
501f4a2713aSLionel Sambuc     switch (C) {
502f4a2713aSLionel Sambuc     case '&':
503f4a2713aSLionel Sambuc       Result << "&amp;";
504f4a2713aSLionel Sambuc       break;
505f4a2713aSLionel Sambuc     case '<':
506f4a2713aSLionel Sambuc       Result << "&lt;";
507f4a2713aSLionel Sambuc       break;
508f4a2713aSLionel Sambuc     case '>':
509f4a2713aSLionel Sambuc       Result << "&gt;";
510f4a2713aSLionel Sambuc       break;
511f4a2713aSLionel Sambuc     case '"':
512f4a2713aSLionel Sambuc       Result << "&quot;";
513f4a2713aSLionel Sambuc       break;
514f4a2713aSLionel Sambuc     case '\'':
515f4a2713aSLionel Sambuc       Result << "&#39;";
516f4a2713aSLionel Sambuc       break;
517f4a2713aSLionel Sambuc     case '/':
518f4a2713aSLionel Sambuc       Result << "&#47;";
519f4a2713aSLionel Sambuc       break;
520f4a2713aSLionel Sambuc     default:
521f4a2713aSLionel Sambuc       Result << C;
522f4a2713aSLionel Sambuc       break;
523f4a2713aSLionel Sambuc     }
524f4a2713aSLionel Sambuc   }
525f4a2713aSLionel Sambuc }
526f4a2713aSLionel Sambuc 
527f4a2713aSLionel Sambuc namespace {
528f4a2713aSLionel Sambuc class CommentASTToXMLConverter :
529f4a2713aSLionel Sambuc     public ConstCommentVisitor<CommentASTToXMLConverter> {
530f4a2713aSLionel Sambuc public:
531f4a2713aSLionel Sambuc   /// \param Str accumulator for XML.
CommentASTToXMLConverter(const FullComment * FC,SmallVectorImpl<char> & Str,const CommandTraits & Traits,const SourceManager & SM,SimpleFormatContext & SFC,unsigned FUID)532f4a2713aSLionel Sambuc   CommentASTToXMLConverter(const FullComment *FC,
533f4a2713aSLionel Sambuc                            SmallVectorImpl<char> &Str,
534f4a2713aSLionel Sambuc                            const CommandTraits &Traits,
535f4a2713aSLionel Sambuc                            const SourceManager &SM,
536f4a2713aSLionel Sambuc                            SimpleFormatContext &SFC,
537f4a2713aSLionel Sambuc                            unsigned FUID) :
538f4a2713aSLionel Sambuc       FC(FC), Result(Str), Traits(Traits), SM(SM),
539f4a2713aSLionel Sambuc       FormatRewriterContext(SFC),
540f4a2713aSLionel Sambuc       FormatInMemoryUniqueId(FUID) { }
541f4a2713aSLionel Sambuc 
542f4a2713aSLionel Sambuc   // Inline content.
543f4a2713aSLionel Sambuc   void visitTextComment(const TextComment *C);
544f4a2713aSLionel Sambuc   void visitInlineCommandComment(const InlineCommandComment *C);
545f4a2713aSLionel Sambuc   void visitHTMLStartTagComment(const HTMLStartTagComment *C);
546f4a2713aSLionel Sambuc   void visitHTMLEndTagComment(const HTMLEndTagComment *C);
547f4a2713aSLionel Sambuc 
548f4a2713aSLionel Sambuc   // Block content.
549f4a2713aSLionel Sambuc   void visitParagraphComment(const ParagraphComment *C);
550f4a2713aSLionel Sambuc 
551f4a2713aSLionel Sambuc   void appendParagraphCommentWithKind(const ParagraphComment *C,
552f4a2713aSLionel Sambuc                                       StringRef Kind);
553f4a2713aSLionel Sambuc 
554f4a2713aSLionel Sambuc   void visitBlockCommandComment(const BlockCommandComment *C);
555f4a2713aSLionel Sambuc   void visitParamCommandComment(const ParamCommandComment *C);
556f4a2713aSLionel Sambuc   void visitTParamCommandComment(const TParamCommandComment *C);
557f4a2713aSLionel Sambuc   void visitVerbatimBlockComment(const VerbatimBlockComment *C);
558f4a2713aSLionel Sambuc   void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
559f4a2713aSLionel Sambuc   void visitVerbatimLineComment(const VerbatimLineComment *C);
560f4a2713aSLionel Sambuc 
561f4a2713aSLionel Sambuc   void visitFullComment(const FullComment *C);
562f4a2713aSLionel Sambuc 
563f4a2713aSLionel Sambuc   // Helpers.
564f4a2713aSLionel Sambuc   void appendToResultWithXMLEscaping(StringRef S);
565*0a6a1f1dSLionel Sambuc   void appendToResultWithCDATAEscaping(StringRef S);
566f4a2713aSLionel Sambuc 
567f4a2713aSLionel Sambuc   void formatTextOfDeclaration(const DeclInfo *DI,
568f4a2713aSLionel Sambuc                                SmallString<128> &Declaration);
569f4a2713aSLionel Sambuc 
570f4a2713aSLionel Sambuc private:
571f4a2713aSLionel Sambuc   const FullComment *FC;
572f4a2713aSLionel Sambuc 
573f4a2713aSLionel Sambuc   /// Output stream for XML.
574f4a2713aSLionel Sambuc   llvm::raw_svector_ostream Result;
575f4a2713aSLionel Sambuc 
576f4a2713aSLionel Sambuc   const CommandTraits &Traits;
577f4a2713aSLionel Sambuc   const SourceManager &SM;
578f4a2713aSLionel Sambuc   SimpleFormatContext &FormatRewriterContext;
579f4a2713aSLionel Sambuc   unsigned FormatInMemoryUniqueId;
580f4a2713aSLionel Sambuc };
581f4a2713aSLionel Sambuc 
getSourceTextOfDeclaration(const DeclInfo * ThisDecl,SmallVectorImpl<char> & Str)582f4a2713aSLionel Sambuc void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
583f4a2713aSLionel Sambuc                                 SmallVectorImpl<char> &Str) {
584f4a2713aSLionel Sambuc   ASTContext &Context = ThisDecl->CurrentDecl->getASTContext();
585f4a2713aSLionel Sambuc   const LangOptions &LangOpts = Context.getLangOpts();
586f4a2713aSLionel Sambuc   llvm::raw_svector_ostream OS(Str);
587f4a2713aSLionel Sambuc   PrintingPolicy PPolicy(LangOpts);
588f4a2713aSLionel Sambuc   PPolicy.PolishForDeclaration = true;
589f4a2713aSLionel Sambuc   PPolicy.TerseOutput = true;
590f4a2713aSLionel Sambuc   ThisDecl->CurrentDecl->print(OS, PPolicy,
591f4a2713aSLionel Sambuc                                /*Indentation*/0, /*PrintInstantiation*/false);
592f4a2713aSLionel Sambuc }
593f4a2713aSLionel Sambuc 
formatTextOfDeclaration(const DeclInfo * DI,SmallString<128> & Declaration)594f4a2713aSLionel Sambuc void CommentASTToXMLConverter::formatTextOfDeclaration(
595f4a2713aSLionel Sambuc     const DeclInfo *DI, SmallString<128> &Declaration) {
596f4a2713aSLionel Sambuc   // FIXME. formatting API expects null terminated input string.
597f4a2713aSLionel Sambuc   // There might be more efficient way of doing this.
598f4a2713aSLionel Sambuc   std::string StringDecl = Declaration.str();
599f4a2713aSLionel Sambuc 
600f4a2713aSLionel Sambuc   // Formatter specific code.
601f4a2713aSLionel Sambuc   // Form a unique in memory buffer name.
602f4a2713aSLionel Sambuc   SmallString<128> filename;
603f4a2713aSLionel Sambuc   filename += "xmldecl";
604f4a2713aSLionel Sambuc   filename += llvm::utostr(FormatInMemoryUniqueId);
605f4a2713aSLionel Sambuc   filename += ".xd";
606f4a2713aSLionel Sambuc   FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
607f4a2713aSLionel Sambuc   SourceLocation Start = FormatRewriterContext.Sources.getLocForStartOfFile(ID)
608f4a2713aSLionel Sambuc       .getLocWithOffset(0);
609f4a2713aSLionel Sambuc   unsigned Length = Declaration.size();
610f4a2713aSLionel Sambuc 
611f4a2713aSLionel Sambuc   tooling::Replacements Replace = reformat(
612*0a6a1f1dSLionel Sambuc       format::getLLVMStyle(), FormatRewriterContext.Sources, ID,
613*0a6a1f1dSLionel Sambuc       CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
614f4a2713aSLionel Sambuc   applyAllReplacements(Replace, FormatRewriterContext.Rewrite);
615f4a2713aSLionel Sambuc   Declaration = FormatRewriterContext.getRewrittenText(ID);
616f4a2713aSLionel Sambuc }
617f4a2713aSLionel Sambuc 
618f4a2713aSLionel Sambuc } // end unnamed namespace
619f4a2713aSLionel Sambuc 
visitTextComment(const TextComment * C)620f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
621f4a2713aSLionel Sambuc   appendToResultWithXMLEscaping(C->getText());
622f4a2713aSLionel Sambuc }
623f4a2713aSLionel Sambuc 
visitInlineCommandComment(const InlineCommandComment * C)624f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitInlineCommandComment(
625f4a2713aSLionel Sambuc     const InlineCommandComment *C) {
626f4a2713aSLionel Sambuc   // Nothing to render if no arguments supplied.
627f4a2713aSLionel Sambuc   if (C->getNumArgs() == 0)
628f4a2713aSLionel Sambuc     return;
629f4a2713aSLionel Sambuc 
630f4a2713aSLionel Sambuc   // Nothing to render if argument is empty.
631f4a2713aSLionel Sambuc   StringRef Arg0 = C->getArgText(0);
632f4a2713aSLionel Sambuc   if (Arg0.empty())
633f4a2713aSLionel Sambuc     return;
634f4a2713aSLionel Sambuc 
635f4a2713aSLionel Sambuc   switch (C->getRenderKind()) {
636f4a2713aSLionel Sambuc   case InlineCommandComment::RenderNormal:
637f4a2713aSLionel Sambuc     for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
638f4a2713aSLionel Sambuc       appendToResultWithXMLEscaping(C->getArgText(i));
639f4a2713aSLionel Sambuc       Result << " ";
640f4a2713aSLionel Sambuc     }
641f4a2713aSLionel Sambuc     return;
642f4a2713aSLionel Sambuc   case InlineCommandComment::RenderBold:
643f4a2713aSLionel Sambuc     assert(C->getNumArgs() == 1);
644f4a2713aSLionel Sambuc     Result << "<bold>";
645f4a2713aSLionel Sambuc     appendToResultWithXMLEscaping(Arg0);
646f4a2713aSLionel Sambuc     Result << "</bold>";
647f4a2713aSLionel Sambuc     return;
648f4a2713aSLionel Sambuc   case InlineCommandComment::RenderMonospaced:
649f4a2713aSLionel Sambuc     assert(C->getNumArgs() == 1);
650f4a2713aSLionel Sambuc     Result << "<monospaced>";
651f4a2713aSLionel Sambuc     appendToResultWithXMLEscaping(Arg0);
652f4a2713aSLionel Sambuc     Result << "</monospaced>";
653f4a2713aSLionel Sambuc     return;
654f4a2713aSLionel Sambuc   case InlineCommandComment::RenderEmphasized:
655f4a2713aSLionel Sambuc     assert(C->getNumArgs() == 1);
656f4a2713aSLionel Sambuc     Result << "<emphasized>";
657f4a2713aSLionel Sambuc     appendToResultWithXMLEscaping(Arg0);
658f4a2713aSLionel Sambuc     Result << "</emphasized>";
659f4a2713aSLionel Sambuc     return;
660f4a2713aSLionel Sambuc   }
661f4a2713aSLionel Sambuc }
662f4a2713aSLionel Sambuc 
visitHTMLStartTagComment(const HTMLStartTagComment * C)663f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitHTMLStartTagComment(
664f4a2713aSLionel Sambuc     const HTMLStartTagComment *C) {
665*0a6a1f1dSLionel Sambuc   Result << "<rawHTML";
666*0a6a1f1dSLionel Sambuc   if (C->isMalformed())
667*0a6a1f1dSLionel Sambuc     Result << " isMalformed=\"1\"";
668*0a6a1f1dSLionel Sambuc   Result << ">";
669*0a6a1f1dSLionel Sambuc   {
670*0a6a1f1dSLionel Sambuc     SmallString<32> Tag;
671*0a6a1f1dSLionel Sambuc     {
672*0a6a1f1dSLionel Sambuc       llvm::raw_svector_ostream TagOS(Tag);
673*0a6a1f1dSLionel Sambuc       printHTMLStartTagComment(C, TagOS);
674*0a6a1f1dSLionel Sambuc     }
675*0a6a1f1dSLionel Sambuc     appendToResultWithCDATAEscaping(Tag);
676*0a6a1f1dSLionel Sambuc   }
677*0a6a1f1dSLionel Sambuc   Result << "</rawHTML>";
678f4a2713aSLionel Sambuc }
679f4a2713aSLionel Sambuc 
680f4a2713aSLionel Sambuc void
visitHTMLEndTagComment(const HTMLEndTagComment * C)681f4a2713aSLionel Sambuc CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
682*0a6a1f1dSLionel Sambuc   Result << "<rawHTML";
683*0a6a1f1dSLionel Sambuc   if (C->isMalformed())
684*0a6a1f1dSLionel Sambuc     Result << " isMalformed=\"1\"";
685*0a6a1f1dSLionel Sambuc   Result << ">&lt;/" << C->getTagName() << "&gt;</rawHTML>";
686f4a2713aSLionel Sambuc }
687f4a2713aSLionel Sambuc 
688f4a2713aSLionel Sambuc void
visitParagraphComment(const ParagraphComment * C)689f4a2713aSLionel Sambuc CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
690f4a2713aSLionel Sambuc   appendParagraphCommentWithKind(C, StringRef());
691f4a2713aSLionel Sambuc }
692f4a2713aSLionel Sambuc 
appendParagraphCommentWithKind(const ParagraphComment * C,StringRef ParagraphKind)693f4a2713aSLionel Sambuc void CommentASTToXMLConverter::appendParagraphCommentWithKind(
694f4a2713aSLionel Sambuc                                   const ParagraphComment *C,
695f4a2713aSLionel Sambuc                                   StringRef ParagraphKind) {
696f4a2713aSLionel Sambuc   if (C->isWhitespace())
697f4a2713aSLionel Sambuc     return;
698f4a2713aSLionel Sambuc 
699f4a2713aSLionel Sambuc   if (ParagraphKind.empty())
700f4a2713aSLionel Sambuc     Result << "<Para>";
701f4a2713aSLionel Sambuc   else
702f4a2713aSLionel Sambuc     Result << "<Para kind=\"" << ParagraphKind << "\">";
703f4a2713aSLionel Sambuc 
704f4a2713aSLionel Sambuc   for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
705f4a2713aSLionel Sambuc        I != E; ++I) {
706f4a2713aSLionel Sambuc     visit(*I);
707f4a2713aSLionel Sambuc   }
708f4a2713aSLionel Sambuc   Result << "</Para>";
709f4a2713aSLionel Sambuc }
710f4a2713aSLionel Sambuc 
visitBlockCommandComment(const BlockCommandComment * C)711f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitBlockCommandComment(
712f4a2713aSLionel Sambuc     const BlockCommandComment *C) {
713f4a2713aSLionel Sambuc   StringRef ParagraphKind;
714f4a2713aSLionel Sambuc 
715f4a2713aSLionel Sambuc   switch (C->getCommandID()) {
716f4a2713aSLionel Sambuc   case CommandTraits::KCI_attention:
717f4a2713aSLionel Sambuc   case CommandTraits::KCI_author:
718f4a2713aSLionel Sambuc   case CommandTraits::KCI_authors:
719f4a2713aSLionel Sambuc   case CommandTraits::KCI_bug:
720f4a2713aSLionel Sambuc   case CommandTraits::KCI_copyright:
721f4a2713aSLionel Sambuc   case CommandTraits::KCI_date:
722f4a2713aSLionel Sambuc   case CommandTraits::KCI_invariant:
723f4a2713aSLionel Sambuc   case CommandTraits::KCI_note:
724f4a2713aSLionel Sambuc   case CommandTraits::KCI_post:
725f4a2713aSLionel Sambuc   case CommandTraits::KCI_pre:
726f4a2713aSLionel Sambuc   case CommandTraits::KCI_remark:
727f4a2713aSLionel Sambuc   case CommandTraits::KCI_remarks:
728f4a2713aSLionel Sambuc   case CommandTraits::KCI_sa:
729f4a2713aSLionel Sambuc   case CommandTraits::KCI_see:
730f4a2713aSLionel Sambuc   case CommandTraits::KCI_since:
731f4a2713aSLionel Sambuc   case CommandTraits::KCI_todo:
732f4a2713aSLionel Sambuc   case CommandTraits::KCI_version:
733f4a2713aSLionel Sambuc   case CommandTraits::KCI_warning:
734f4a2713aSLionel Sambuc     ParagraphKind = C->getCommandName(Traits);
735f4a2713aSLionel Sambuc   default:
736f4a2713aSLionel Sambuc     break;
737f4a2713aSLionel Sambuc   }
738f4a2713aSLionel Sambuc 
739f4a2713aSLionel Sambuc   appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind);
740f4a2713aSLionel Sambuc }
741f4a2713aSLionel Sambuc 
visitParamCommandComment(const ParamCommandComment * C)742f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitParamCommandComment(
743f4a2713aSLionel Sambuc     const ParamCommandComment *C) {
744f4a2713aSLionel Sambuc   Result << "<Parameter><Name>";
745f4a2713aSLionel Sambuc   appendToResultWithXMLEscaping(C->isParamIndexValid()
746f4a2713aSLionel Sambuc                                     ? C->getParamName(FC)
747f4a2713aSLionel Sambuc                                     : C->getParamNameAsWritten());
748f4a2713aSLionel Sambuc   Result << "</Name>";
749f4a2713aSLionel Sambuc 
750f4a2713aSLionel Sambuc   if (C->isParamIndexValid()) {
751f4a2713aSLionel Sambuc     if (C->isVarArgParam())
752f4a2713aSLionel Sambuc       Result << "<IsVarArg />";
753f4a2713aSLionel Sambuc     else
754f4a2713aSLionel Sambuc       Result << "<Index>" << C->getParamIndex() << "</Index>";
755f4a2713aSLionel Sambuc   }
756f4a2713aSLionel Sambuc 
757f4a2713aSLionel Sambuc   Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">";
758f4a2713aSLionel Sambuc   switch (C->getDirection()) {
759f4a2713aSLionel Sambuc   case ParamCommandComment::In:
760f4a2713aSLionel Sambuc     Result << "in";
761f4a2713aSLionel Sambuc     break;
762f4a2713aSLionel Sambuc   case ParamCommandComment::Out:
763f4a2713aSLionel Sambuc     Result << "out";
764f4a2713aSLionel Sambuc     break;
765f4a2713aSLionel Sambuc   case ParamCommandComment::InOut:
766f4a2713aSLionel Sambuc     Result << "in,out";
767f4a2713aSLionel Sambuc     break;
768f4a2713aSLionel Sambuc   }
769f4a2713aSLionel Sambuc   Result << "</Direction><Discussion>";
770f4a2713aSLionel Sambuc   visit(C->getParagraph());
771f4a2713aSLionel Sambuc   Result << "</Discussion></Parameter>";
772f4a2713aSLionel Sambuc }
773f4a2713aSLionel Sambuc 
visitTParamCommandComment(const TParamCommandComment * C)774f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitTParamCommandComment(
775f4a2713aSLionel Sambuc                                   const TParamCommandComment *C) {
776f4a2713aSLionel Sambuc   Result << "<Parameter><Name>";
777f4a2713aSLionel Sambuc   appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
778f4a2713aSLionel Sambuc                                 : C->getParamNameAsWritten());
779f4a2713aSLionel Sambuc   Result << "</Name>";
780f4a2713aSLionel Sambuc 
781f4a2713aSLionel Sambuc   if (C->isPositionValid() && C->getDepth() == 1) {
782f4a2713aSLionel Sambuc     Result << "<Index>" << C->getIndex(0) << "</Index>";
783f4a2713aSLionel Sambuc   }
784f4a2713aSLionel Sambuc 
785f4a2713aSLionel Sambuc   Result << "<Discussion>";
786f4a2713aSLionel Sambuc   visit(C->getParagraph());
787f4a2713aSLionel Sambuc   Result << "</Discussion></Parameter>";
788f4a2713aSLionel Sambuc }
789f4a2713aSLionel Sambuc 
visitVerbatimBlockComment(const VerbatimBlockComment * C)790f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitVerbatimBlockComment(
791f4a2713aSLionel Sambuc                                   const VerbatimBlockComment *C) {
792f4a2713aSLionel Sambuc   unsigned NumLines = C->getNumLines();
793f4a2713aSLionel Sambuc   if (NumLines == 0)
794f4a2713aSLionel Sambuc     return;
795f4a2713aSLionel Sambuc 
796f4a2713aSLionel Sambuc   switch (C->getCommandID()) {
797f4a2713aSLionel Sambuc   case CommandTraits::KCI_code:
798f4a2713aSLionel Sambuc     Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">";
799f4a2713aSLionel Sambuc     break;
800f4a2713aSLionel Sambuc   default:
801f4a2713aSLionel Sambuc     Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
802f4a2713aSLionel Sambuc     break;
803f4a2713aSLionel Sambuc   }
804f4a2713aSLionel Sambuc   for (unsigned i = 0; i != NumLines; ++i) {
805f4a2713aSLionel Sambuc     appendToResultWithXMLEscaping(C->getText(i));
806f4a2713aSLionel Sambuc     if (i + 1 != NumLines)
807f4a2713aSLionel Sambuc       Result << '\n';
808f4a2713aSLionel Sambuc   }
809f4a2713aSLionel Sambuc   Result << "</Verbatim>";
810f4a2713aSLionel Sambuc }
811f4a2713aSLionel Sambuc 
visitVerbatimBlockLineComment(const VerbatimBlockLineComment * C)812f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
813f4a2713aSLionel Sambuc                                   const VerbatimBlockLineComment *C) {
814f4a2713aSLionel Sambuc   llvm_unreachable("should not see this AST node");
815f4a2713aSLionel Sambuc }
816f4a2713aSLionel Sambuc 
visitVerbatimLineComment(const VerbatimLineComment * C)817f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitVerbatimLineComment(
818f4a2713aSLionel Sambuc                                   const VerbatimLineComment *C) {
819f4a2713aSLionel Sambuc   Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
820f4a2713aSLionel Sambuc   appendToResultWithXMLEscaping(C->getText());
821f4a2713aSLionel Sambuc   Result << "</Verbatim>";
822f4a2713aSLionel Sambuc }
823f4a2713aSLionel Sambuc 
visitFullComment(const FullComment * C)824f4a2713aSLionel Sambuc void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
825f4a2713aSLionel Sambuc   FullCommentParts Parts(C, Traits);
826f4a2713aSLionel Sambuc 
827f4a2713aSLionel Sambuc   const DeclInfo *DI = C->getDeclInfo();
828f4a2713aSLionel Sambuc   StringRef RootEndTag;
829f4a2713aSLionel Sambuc   if (DI) {
830f4a2713aSLionel Sambuc     switch (DI->getKind()) {
831f4a2713aSLionel Sambuc     case DeclInfo::OtherKind:
832f4a2713aSLionel Sambuc       RootEndTag = "</Other>";
833f4a2713aSLionel Sambuc       Result << "<Other";
834f4a2713aSLionel Sambuc       break;
835f4a2713aSLionel Sambuc     case DeclInfo::FunctionKind:
836f4a2713aSLionel Sambuc       RootEndTag = "</Function>";
837f4a2713aSLionel Sambuc       Result << "<Function";
838f4a2713aSLionel Sambuc       switch (DI->TemplateKind) {
839f4a2713aSLionel Sambuc       case DeclInfo::NotTemplate:
840f4a2713aSLionel Sambuc         break;
841f4a2713aSLionel Sambuc       case DeclInfo::Template:
842f4a2713aSLionel Sambuc         Result << " templateKind=\"template\"";
843f4a2713aSLionel Sambuc         break;
844f4a2713aSLionel Sambuc       case DeclInfo::TemplateSpecialization:
845f4a2713aSLionel Sambuc         Result << " templateKind=\"specialization\"";
846f4a2713aSLionel Sambuc         break;
847f4a2713aSLionel Sambuc       case DeclInfo::TemplatePartialSpecialization:
848f4a2713aSLionel Sambuc         llvm_unreachable("partial specializations of functions "
849f4a2713aSLionel Sambuc                          "are not allowed in C++");
850f4a2713aSLionel Sambuc       }
851f4a2713aSLionel Sambuc       if (DI->IsInstanceMethod)
852f4a2713aSLionel Sambuc         Result << " isInstanceMethod=\"1\"";
853f4a2713aSLionel Sambuc       if (DI->IsClassMethod)
854f4a2713aSLionel Sambuc         Result << " isClassMethod=\"1\"";
855f4a2713aSLionel Sambuc       break;
856f4a2713aSLionel Sambuc     case DeclInfo::ClassKind:
857f4a2713aSLionel Sambuc       RootEndTag = "</Class>";
858f4a2713aSLionel Sambuc       Result << "<Class";
859f4a2713aSLionel Sambuc       switch (DI->TemplateKind) {
860f4a2713aSLionel Sambuc       case DeclInfo::NotTemplate:
861f4a2713aSLionel Sambuc         break;
862f4a2713aSLionel Sambuc       case DeclInfo::Template:
863f4a2713aSLionel Sambuc         Result << " templateKind=\"template\"";
864f4a2713aSLionel Sambuc         break;
865f4a2713aSLionel Sambuc       case DeclInfo::TemplateSpecialization:
866f4a2713aSLionel Sambuc         Result << " templateKind=\"specialization\"";
867f4a2713aSLionel Sambuc         break;
868f4a2713aSLionel Sambuc       case DeclInfo::TemplatePartialSpecialization:
869f4a2713aSLionel Sambuc         Result << " templateKind=\"partialSpecialization\"";
870f4a2713aSLionel Sambuc         break;
871f4a2713aSLionel Sambuc       }
872f4a2713aSLionel Sambuc       break;
873f4a2713aSLionel Sambuc     case DeclInfo::VariableKind:
874f4a2713aSLionel Sambuc       RootEndTag = "</Variable>";
875f4a2713aSLionel Sambuc       Result << "<Variable";
876f4a2713aSLionel Sambuc       break;
877f4a2713aSLionel Sambuc     case DeclInfo::NamespaceKind:
878f4a2713aSLionel Sambuc       RootEndTag = "</Namespace>";
879f4a2713aSLionel Sambuc       Result << "<Namespace";
880f4a2713aSLionel Sambuc       break;
881f4a2713aSLionel Sambuc     case DeclInfo::TypedefKind:
882f4a2713aSLionel Sambuc       RootEndTag = "</Typedef>";
883f4a2713aSLionel Sambuc       Result << "<Typedef";
884f4a2713aSLionel Sambuc       break;
885f4a2713aSLionel Sambuc     case DeclInfo::EnumKind:
886f4a2713aSLionel Sambuc       RootEndTag = "</Enum>";
887f4a2713aSLionel Sambuc       Result << "<Enum";
888f4a2713aSLionel Sambuc       break;
889f4a2713aSLionel Sambuc     }
890f4a2713aSLionel Sambuc 
891f4a2713aSLionel Sambuc     {
892f4a2713aSLionel Sambuc       // Print line and column number.
893f4a2713aSLionel Sambuc       SourceLocation Loc = DI->CurrentDecl->getLocation();
894f4a2713aSLionel Sambuc       std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
895f4a2713aSLionel Sambuc       FileID FID = LocInfo.first;
896f4a2713aSLionel Sambuc       unsigned FileOffset = LocInfo.second;
897f4a2713aSLionel Sambuc 
898f4a2713aSLionel Sambuc       if (!FID.isInvalid()) {
899f4a2713aSLionel Sambuc         if (const FileEntry *FE = SM.getFileEntryForID(FID)) {
900f4a2713aSLionel Sambuc           Result << " file=\"";
901f4a2713aSLionel Sambuc           appendToResultWithXMLEscaping(FE->getName());
902f4a2713aSLionel Sambuc           Result << "\"";
903f4a2713aSLionel Sambuc         }
904f4a2713aSLionel Sambuc         Result << " line=\"" << SM.getLineNumber(FID, FileOffset)
905f4a2713aSLionel Sambuc                << "\" column=\"" << SM.getColumnNumber(FID, FileOffset)
906f4a2713aSLionel Sambuc                << "\"";
907f4a2713aSLionel Sambuc       }
908f4a2713aSLionel Sambuc     }
909f4a2713aSLionel Sambuc 
910f4a2713aSLionel Sambuc     // Finish the root tag.
911f4a2713aSLionel Sambuc     Result << ">";
912f4a2713aSLionel Sambuc 
913f4a2713aSLionel Sambuc     bool FoundName = false;
914f4a2713aSLionel Sambuc     if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
915f4a2713aSLionel Sambuc       if (DeclarationName DeclName = ND->getDeclName()) {
916f4a2713aSLionel Sambuc         Result << "<Name>";
917f4a2713aSLionel Sambuc         std::string Name = DeclName.getAsString();
918f4a2713aSLionel Sambuc         appendToResultWithXMLEscaping(Name);
919f4a2713aSLionel Sambuc         FoundName = true;
920f4a2713aSLionel Sambuc         Result << "</Name>";
921f4a2713aSLionel Sambuc       }
922f4a2713aSLionel Sambuc     }
923f4a2713aSLionel Sambuc     if (!FoundName)
924f4a2713aSLionel Sambuc       Result << "<Name>&lt;anonymous&gt;</Name>";
925f4a2713aSLionel Sambuc 
926f4a2713aSLionel Sambuc     {
927f4a2713aSLionel Sambuc       // Print USR.
928f4a2713aSLionel Sambuc       SmallString<128> USR;
929f4a2713aSLionel Sambuc       generateUSRForDecl(DI->CommentDecl, USR);
930f4a2713aSLionel Sambuc       if (!USR.empty()) {
931f4a2713aSLionel Sambuc         Result << "<USR>";
932f4a2713aSLionel Sambuc         appendToResultWithXMLEscaping(USR);
933f4a2713aSLionel Sambuc         Result << "</USR>";
934f4a2713aSLionel Sambuc       }
935f4a2713aSLionel Sambuc     }
936f4a2713aSLionel Sambuc   } else {
937f4a2713aSLionel Sambuc     // No DeclInfo -- just emit some root tag and name tag.
938f4a2713aSLionel Sambuc     RootEndTag = "</Other>";
939f4a2713aSLionel Sambuc     Result << "<Other><Name>unknown</Name>";
940f4a2713aSLionel Sambuc   }
941f4a2713aSLionel Sambuc 
942f4a2713aSLionel Sambuc   if (Parts.Headerfile) {
943f4a2713aSLionel Sambuc     Result << "<Headerfile>";
944f4a2713aSLionel Sambuc     visit(Parts.Headerfile);
945f4a2713aSLionel Sambuc     Result << "</Headerfile>";
946f4a2713aSLionel Sambuc   }
947f4a2713aSLionel Sambuc 
948f4a2713aSLionel Sambuc   {
949f4a2713aSLionel Sambuc     // Pretty-print the declaration.
950f4a2713aSLionel Sambuc     Result << "<Declaration>";
951f4a2713aSLionel Sambuc     SmallString<128> Declaration;
952f4a2713aSLionel Sambuc     getSourceTextOfDeclaration(DI, Declaration);
953f4a2713aSLionel Sambuc     formatTextOfDeclaration(DI, Declaration);
954f4a2713aSLionel Sambuc     appendToResultWithXMLEscaping(Declaration);
955f4a2713aSLionel Sambuc     Result << "</Declaration>";
956f4a2713aSLionel Sambuc   }
957f4a2713aSLionel Sambuc 
958f4a2713aSLionel Sambuc   bool FirstParagraphIsBrief = false;
959f4a2713aSLionel Sambuc   if (Parts.Brief) {
960f4a2713aSLionel Sambuc     Result << "<Abstract>";
961f4a2713aSLionel Sambuc     visit(Parts.Brief);
962f4a2713aSLionel Sambuc     Result << "</Abstract>";
963f4a2713aSLionel Sambuc   } else if (Parts.FirstParagraph) {
964f4a2713aSLionel Sambuc     Result << "<Abstract>";
965f4a2713aSLionel Sambuc     visit(Parts.FirstParagraph);
966f4a2713aSLionel Sambuc     Result << "</Abstract>";
967f4a2713aSLionel Sambuc     FirstParagraphIsBrief = true;
968f4a2713aSLionel Sambuc   }
969f4a2713aSLionel Sambuc 
970f4a2713aSLionel Sambuc   if (Parts.TParams.size() != 0) {
971f4a2713aSLionel Sambuc     Result << "<TemplateParameters>";
972f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
973f4a2713aSLionel Sambuc       visit(Parts.TParams[i]);
974f4a2713aSLionel Sambuc     Result << "</TemplateParameters>";
975f4a2713aSLionel Sambuc   }
976f4a2713aSLionel Sambuc 
977f4a2713aSLionel Sambuc   if (Parts.Params.size() != 0) {
978f4a2713aSLionel Sambuc     Result << "<Parameters>";
979f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
980f4a2713aSLionel Sambuc       visit(Parts.Params[i]);
981f4a2713aSLionel Sambuc     Result << "</Parameters>";
982f4a2713aSLionel Sambuc   }
983f4a2713aSLionel Sambuc 
984f4a2713aSLionel Sambuc   if (Parts.Exceptions.size() != 0) {
985f4a2713aSLionel Sambuc     Result << "<Exceptions>";
986f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
987f4a2713aSLionel Sambuc       visit(Parts.Exceptions[i]);
988f4a2713aSLionel Sambuc     Result << "</Exceptions>";
989f4a2713aSLionel Sambuc   }
990f4a2713aSLionel Sambuc 
991f4a2713aSLionel Sambuc   if (Parts.Returns.size() != 0) {
992f4a2713aSLionel Sambuc     Result << "<ResultDiscussion>";
993f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
994f4a2713aSLionel Sambuc       visit(Parts.Returns[i]);
995f4a2713aSLionel Sambuc     Result << "</ResultDiscussion>";
996f4a2713aSLionel Sambuc   }
997f4a2713aSLionel Sambuc 
998f4a2713aSLionel Sambuc   if (DI->CommentDecl->hasAttrs()) {
999f4a2713aSLionel Sambuc     const AttrVec &Attrs = DI->CommentDecl->getAttrs();
1000f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Attrs.size(); i != e; i++) {
1001f4a2713aSLionel Sambuc       const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
1002f4a2713aSLionel Sambuc       if (!AA) {
1003f4a2713aSLionel Sambuc         if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
1004f4a2713aSLionel Sambuc           if (DA->getMessage().empty())
1005f4a2713aSLionel Sambuc             Result << "<Deprecated/>";
1006f4a2713aSLionel Sambuc           else {
1007f4a2713aSLionel Sambuc             Result << "<Deprecated>";
1008f4a2713aSLionel Sambuc             appendToResultWithXMLEscaping(DA->getMessage());
1009f4a2713aSLionel Sambuc             Result << "</Deprecated>";
1010f4a2713aSLionel Sambuc           }
1011f4a2713aSLionel Sambuc         }
1012f4a2713aSLionel Sambuc         else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1013f4a2713aSLionel Sambuc           if (UA->getMessage().empty())
1014f4a2713aSLionel Sambuc             Result << "<Unavailable/>";
1015f4a2713aSLionel Sambuc           else {
1016f4a2713aSLionel Sambuc             Result << "<Unavailable>";
1017f4a2713aSLionel Sambuc             appendToResultWithXMLEscaping(UA->getMessage());
1018f4a2713aSLionel Sambuc             Result << "</Unavailable>";
1019f4a2713aSLionel Sambuc           }
1020f4a2713aSLionel Sambuc         }
1021f4a2713aSLionel Sambuc         continue;
1022f4a2713aSLionel Sambuc       }
1023f4a2713aSLionel Sambuc 
1024f4a2713aSLionel Sambuc       // 'availability' attribute.
1025f4a2713aSLionel Sambuc       Result << "<Availability";
1026f4a2713aSLionel Sambuc       StringRef Distribution;
1027f4a2713aSLionel Sambuc       if (AA->getPlatform()) {
1028f4a2713aSLionel Sambuc         Distribution = AvailabilityAttr::getPrettyPlatformName(
1029f4a2713aSLionel Sambuc                                         AA->getPlatform()->getName());
1030f4a2713aSLionel Sambuc         if (Distribution.empty())
1031f4a2713aSLionel Sambuc           Distribution = AA->getPlatform()->getName();
1032f4a2713aSLionel Sambuc       }
1033f4a2713aSLionel Sambuc       Result << " distribution=\"" << Distribution << "\">";
1034f4a2713aSLionel Sambuc       VersionTuple IntroducedInVersion = AA->getIntroduced();
1035f4a2713aSLionel Sambuc       if (!IntroducedInVersion.empty()) {
1036f4a2713aSLionel Sambuc         Result << "<IntroducedInVersion>"
1037f4a2713aSLionel Sambuc                << IntroducedInVersion.getAsString()
1038f4a2713aSLionel Sambuc                << "</IntroducedInVersion>";
1039f4a2713aSLionel Sambuc       }
1040f4a2713aSLionel Sambuc       VersionTuple DeprecatedInVersion = AA->getDeprecated();
1041f4a2713aSLionel Sambuc       if (!DeprecatedInVersion.empty()) {
1042f4a2713aSLionel Sambuc         Result << "<DeprecatedInVersion>"
1043f4a2713aSLionel Sambuc                << DeprecatedInVersion.getAsString()
1044f4a2713aSLionel Sambuc                << "</DeprecatedInVersion>";
1045f4a2713aSLionel Sambuc       }
1046f4a2713aSLionel Sambuc       VersionTuple RemovedAfterVersion = AA->getObsoleted();
1047f4a2713aSLionel Sambuc       if (!RemovedAfterVersion.empty()) {
1048f4a2713aSLionel Sambuc         Result << "<RemovedAfterVersion>"
1049f4a2713aSLionel Sambuc                << RemovedAfterVersion.getAsString()
1050f4a2713aSLionel Sambuc                << "</RemovedAfterVersion>";
1051f4a2713aSLionel Sambuc       }
1052f4a2713aSLionel Sambuc       StringRef DeprecationSummary = AA->getMessage();
1053f4a2713aSLionel Sambuc       if (!DeprecationSummary.empty()) {
1054f4a2713aSLionel Sambuc         Result << "<DeprecationSummary>";
1055f4a2713aSLionel Sambuc         appendToResultWithXMLEscaping(DeprecationSummary);
1056f4a2713aSLionel Sambuc         Result << "</DeprecationSummary>";
1057f4a2713aSLionel Sambuc       }
1058f4a2713aSLionel Sambuc       if (AA->getUnavailable())
1059f4a2713aSLionel Sambuc         Result << "<Unavailable/>";
1060f4a2713aSLionel Sambuc       Result << "</Availability>";
1061f4a2713aSLionel Sambuc     }
1062f4a2713aSLionel Sambuc   }
1063f4a2713aSLionel Sambuc 
1064f4a2713aSLionel Sambuc   {
1065f4a2713aSLionel Sambuc     bool StartTagEmitted = false;
1066f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1067f4a2713aSLionel Sambuc       const Comment *C = Parts.MiscBlocks[i];
1068f4a2713aSLionel Sambuc       if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1069f4a2713aSLionel Sambuc         continue;
1070f4a2713aSLionel Sambuc       if (!StartTagEmitted) {
1071f4a2713aSLionel Sambuc         Result << "<Discussion>";
1072f4a2713aSLionel Sambuc         StartTagEmitted = true;
1073f4a2713aSLionel Sambuc       }
1074f4a2713aSLionel Sambuc       visit(C);
1075f4a2713aSLionel Sambuc     }
1076f4a2713aSLionel Sambuc     if (StartTagEmitted)
1077f4a2713aSLionel Sambuc       Result << "</Discussion>";
1078f4a2713aSLionel Sambuc   }
1079f4a2713aSLionel Sambuc 
1080f4a2713aSLionel Sambuc   Result << RootEndTag;
1081f4a2713aSLionel Sambuc 
1082f4a2713aSLionel Sambuc   Result.flush();
1083f4a2713aSLionel Sambuc }
1084f4a2713aSLionel Sambuc 
appendToResultWithXMLEscaping(StringRef S)1085f4a2713aSLionel Sambuc void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1086f4a2713aSLionel Sambuc   for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
1087f4a2713aSLionel Sambuc     const char C = *I;
1088f4a2713aSLionel Sambuc     switch (C) {
1089f4a2713aSLionel Sambuc     case '&':
1090f4a2713aSLionel Sambuc       Result << "&amp;";
1091f4a2713aSLionel Sambuc       break;
1092f4a2713aSLionel Sambuc     case '<':
1093f4a2713aSLionel Sambuc       Result << "&lt;";
1094f4a2713aSLionel Sambuc       break;
1095f4a2713aSLionel Sambuc     case '>':
1096f4a2713aSLionel Sambuc       Result << "&gt;";
1097f4a2713aSLionel Sambuc       break;
1098f4a2713aSLionel Sambuc     case '"':
1099f4a2713aSLionel Sambuc       Result << "&quot;";
1100f4a2713aSLionel Sambuc       break;
1101f4a2713aSLionel Sambuc     case '\'':
1102f4a2713aSLionel Sambuc       Result << "&apos;";
1103f4a2713aSLionel Sambuc       break;
1104f4a2713aSLionel Sambuc     default:
1105f4a2713aSLionel Sambuc       Result << C;
1106f4a2713aSLionel Sambuc       break;
1107f4a2713aSLionel Sambuc     }
1108f4a2713aSLionel Sambuc   }
1109f4a2713aSLionel Sambuc }
1110f4a2713aSLionel Sambuc 
appendToResultWithCDATAEscaping(StringRef S)1111*0a6a1f1dSLionel Sambuc void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1112*0a6a1f1dSLionel Sambuc   if (S.empty())
1113*0a6a1f1dSLionel Sambuc     return;
1114*0a6a1f1dSLionel Sambuc 
1115*0a6a1f1dSLionel Sambuc   Result << "<![CDATA[";
1116*0a6a1f1dSLionel Sambuc   while (!S.empty()) {
1117*0a6a1f1dSLionel Sambuc     size_t Pos = S.find("]]>");
1118*0a6a1f1dSLionel Sambuc     if (Pos == 0) {
1119*0a6a1f1dSLionel Sambuc       Result << "]]]]><![CDATA[>";
1120*0a6a1f1dSLionel Sambuc       S = S.drop_front(3);
1121*0a6a1f1dSLionel Sambuc       continue;
1122*0a6a1f1dSLionel Sambuc     }
1123*0a6a1f1dSLionel Sambuc     if (Pos == StringRef::npos)
1124*0a6a1f1dSLionel Sambuc       Pos = S.size();
1125*0a6a1f1dSLionel Sambuc 
1126*0a6a1f1dSLionel Sambuc     Result << S.substr(0, Pos);
1127*0a6a1f1dSLionel Sambuc 
1128*0a6a1f1dSLionel Sambuc     S = S.drop_front(Pos);
1129*0a6a1f1dSLionel Sambuc   }
1130*0a6a1f1dSLionel Sambuc   Result << "]]>";
1131*0a6a1f1dSLionel Sambuc }
1132*0a6a1f1dSLionel Sambuc 
CommentToXMLConverter()1133*0a6a1f1dSLionel Sambuc CommentToXMLConverter::CommentToXMLConverter() : FormatInMemoryUniqueId(0) {}
~CommentToXMLConverter()1134*0a6a1f1dSLionel Sambuc CommentToXMLConverter::~CommentToXMLConverter() {}
1135*0a6a1f1dSLionel Sambuc 
convertCommentToHTML(const FullComment * FC,SmallVectorImpl<char> & HTML,const ASTContext & Context)1136f4a2713aSLionel Sambuc void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC,
1137f4a2713aSLionel Sambuc                                                  SmallVectorImpl<char> &HTML,
1138f4a2713aSLionel Sambuc                                                  const ASTContext &Context) {
1139f4a2713aSLionel Sambuc   CommentASTToHTMLConverter Converter(FC, HTML,
1140f4a2713aSLionel Sambuc                                       Context.getCommentCommandTraits());
1141f4a2713aSLionel Sambuc   Converter.visit(FC);
1142f4a2713aSLionel Sambuc }
1143f4a2713aSLionel Sambuc 
convertHTMLTagNodeToText(const comments::HTMLTagComment * HTC,SmallVectorImpl<char> & Text,const ASTContext & Context)1144f4a2713aSLionel Sambuc void CommentToXMLConverter::convertHTMLTagNodeToText(
1145f4a2713aSLionel Sambuc     const comments::HTMLTagComment *HTC, SmallVectorImpl<char> &Text,
1146f4a2713aSLionel Sambuc     const ASTContext &Context) {
1147*0a6a1f1dSLionel Sambuc   CommentASTToHTMLConverter Converter(nullptr, Text,
1148f4a2713aSLionel Sambuc                                       Context.getCommentCommandTraits());
1149f4a2713aSLionel Sambuc   Converter.visit(HTC);
1150f4a2713aSLionel Sambuc }
1151f4a2713aSLionel Sambuc 
convertCommentToXML(const FullComment * FC,SmallVectorImpl<char> & XML,const ASTContext & Context)1152f4a2713aSLionel Sambuc void CommentToXMLConverter::convertCommentToXML(const FullComment *FC,
1153f4a2713aSLionel Sambuc                                                 SmallVectorImpl<char> &XML,
1154f4a2713aSLionel Sambuc                                                 const ASTContext &Context) {
1155*0a6a1f1dSLionel Sambuc   if (!FormatContext || (FormatInMemoryUniqueId % 1000) == 0) {
1156*0a6a1f1dSLionel Sambuc     // Create a new format context, or re-create it after some number of
1157*0a6a1f1dSLionel Sambuc     // iterations, so the buffers don't grow too large.
1158*0a6a1f1dSLionel Sambuc     FormatContext.reset(new SimpleFormatContext(Context.getLangOpts()));
1159f4a2713aSLionel Sambuc   }
1160f4a2713aSLionel Sambuc 
1161f4a2713aSLionel Sambuc   CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(),
1162f4a2713aSLionel Sambuc                                      Context.getSourceManager(), *FormatContext,
1163f4a2713aSLionel Sambuc                                      FormatInMemoryUniqueId++);
1164f4a2713aSLionel Sambuc   Converter.visit(FC);
1165f4a2713aSLionel Sambuc }
1166f4a2713aSLionel Sambuc 
1167