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 << "&";
504f4a2713aSLionel Sambuc break;
505f4a2713aSLionel Sambuc case '<':
506f4a2713aSLionel Sambuc Result << "<";
507f4a2713aSLionel Sambuc break;
508f4a2713aSLionel Sambuc case '>':
509f4a2713aSLionel Sambuc Result << ">";
510f4a2713aSLionel Sambuc break;
511f4a2713aSLionel Sambuc case '"':
512f4a2713aSLionel Sambuc Result << """;
513f4a2713aSLionel Sambuc break;
514f4a2713aSLionel Sambuc case '\'':
515f4a2713aSLionel Sambuc Result << "'";
516f4a2713aSLionel Sambuc break;
517f4a2713aSLionel Sambuc case '/':
518f4a2713aSLionel Sambuc Result << "/";
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 << "></" << C->getTagName() << "></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><anonymous></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 << "&";
1091f4a2713aSLionel Sambuc break;
1092f4a2713aSLionel Sambuc case '<':
1093f4a2713aSLionel Sambuc Result << "<";
1094f4a2713aSLionel Sambuc break;
1095f4a2713aSLionel Sambuc case '>':
1096f4a2713aSLionel Sambuc Result << ">";
1097f4a2713aSLionel Sambuc break;
1098f4a2713aSLionel Sambuc case '"':
1099f4a2713aSLionel Sambuc Result << """;
1100f4a2713aSLionel Sambuc break;
1101f4a2713aSLionel Sambuc case '\'':
1102f4a2713aSLionel Sambuc Result << "'";
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