12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151 |
- //===--- CommentToXML.cpp - Convert comments to XML representation --------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Index/CommentToXML.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/Attr.h"
- #include "clang/AST/Comment.h"
- #include "clang/AST/CommentVisitor.h"
- #include "clang/Basic/FileManager.h"
- #include "clang/Basic/SourceManager.h"
- #include "clang/Format/Format.h"
- #include "clang/Index/USRGeneration.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/ADT/TinyPtrVector.h"
- #include "llvm/Support/raw_ostream.h"
- using namespace clang;
- using namespace clang::comments;
- using namespace clang::index;
- namespace {
- /// This comparison will sort parameters with valid index by index, then vararg
- /// parameters, and invalid (unresolved) parameters last.
- class ParamCommandCommentCompareIndex {
- public:
- bool operator()(const ParamCommandComment *LHS,
- const ParamCommandComment *RHS) const {
- unsigned LHSIndex = UINT_MAX;
- unsigned RHSIndex = UINT_MAX;
- if (LHS->isParamIndexValid()) {
- if (LHS->isVarArgParam())
- LHSIndex = UINT_MAX - 1;
- else
- LHSIndex = LHS->getParamIndex();
- }
- if (RHS->isParamIndexValid()) {
- if (RHS->isVarArgParam())
- RHSIndex = UINT_MAX - 1;
- else
- RHSIndex = RHS->getParamIndex();
- }
- return LHSIndex < RHSIndex;
- }
- };
- /// This comparison will sort template parameters in the following order:
- /// \li real template parameters (depth = 1) in index order;
- /// \li all other names (depth > 1);
- /// \li unresolved names.
- class TParamCommandCommentComparePosition {
- public:
- bool operator()(const TParamCommandComment *LHS,
- const TParamCommandComment *RHS) const {
- // Sort unresolved names last.
- if (!LHS->isPositionValid())
- return false;
- if (!RHS->isPositionValid())
- return true;
- if (LHS->getDepth() > 1)
- return false;
- if (RHS->getDepth() > 1)
- return true;
- // Sort template parameters in index order.
- if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
- return LHS->getIndex(0) < RHS->getIndex(0);
- // Leave all other names in source order.
- return true;
- }
- };
- /// Separate parts of a FullComment.
- struct FullCommentParts {
- /// Take a full comment apart and initialize members accordingly.
- FullCommentParts(const FullComment *C,
- const CommandTraits &Traits);
- const BlockContentComment *Brief;
- const BlockContentComment *Headerfile;
- const ParagraphComment *FirstParagraph;
- SmallVector<const BlockCommandComment *, 4> Returns;
- SmallVector<const ParamCommandComment *, 8> Params;
- SmallVector<const TParamCommandComment *, 4> TParams;
- llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
- SmallVector<const BlockContentComment *, 8> MiscBlocks;
- };
- FullCommentParts::FullCommentParts(const FullComment *C,
- const CommandTraits &Traits) :
- Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I) {
- const Comment *Child = *I;
- if (!Child)
- continue;
- switch (Child->getCommentKind()) {
- case Comment::NoCommentKind:
- continue;
- case Comment::ParagraphCommentKind: {
- const ParagraphComment *PC = cast<ParagraphComment>(Child);
- if (PC->isWhitespace())
- break;
- if (!FirstParagraph)
- FirstParagraph = PC;
- MiscBlocks.push_back(PC);
- break;
- }
- case Comment::BlockCommandCommentKind: {
- const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
- const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
- if (!Brief && Info->IsBriefCommand) {
- Brief = BCC;
- break;
- }
- if (!Headerfile && Info->IsHeaderfileCommand) {
- Headerfile = BCC;
- break;
- }
- if (Info->IsReturnsCommand) {
- Returns.push_back(BCC);
- break;
- }
- if (Info->IsThrowsCommand) {
- Exceptions.push_back(BCC);
- break;
- }
- MiscBlocks.push_back(BCC);
- break;
- }
- case Comment::ParamCommandCommentKind: {
- const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
- if (!PCC->hasParamName())
- break;
- if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
- break;
- Params.push_back(PCC);
- break;
- }
- case Comment::TParamCommandCommentKind: {
- const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
- if (!TPCC->hasParamName())
- break;
- if (!TPCC->hasNonWhitespaceParagraph())
- break;
- TParams.push_back(TPCC);
- break;
- }
- case Comment::VerbatimBlockCommentKind:
- MiscBlocks.push_back(cast<BlockCommandComment>(Child));
- break;
- case Comment::VerbatimLineCommentKind: {
- const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
- const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
- if (!Info->IsDeclarationCommand)
- MiscBlocks.push_back(VLC);
- break;
- }
- case Comment::TextCommentKind:
- case Comment::InlineCommandCommentKind:
- case Comment::HTMLStartTagCommentKind:
- case Comment::HTMLEndTagCommentKind:
- case Comment::VerbatimBlockLineCommentKind:
- case Comment::FullCommentKind:
- llvm_unreachable("AST node of this kind can't be a child of "
- "a FullComment");
- }
- }
- // Sort params in order they are declared in the function prototype.
- // Unresolved parameters are put at the end of the list in the same order
- // they were seen in the comment.
- llvm::stable_sort(Params, ParamCommandCommentCompareIndex());
- llvm::stable_sort(TParams, TParamCommandCommentComparePosition());
- }
- void printHTMLStartTagComment(const HTMLStartTagComment *C,
- llvm::raw_svector_ostream &Result) {
- Result << "<" << C->getTagName();
- if (C->getNumAttrs() != 0) {
- for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
- Result << " ";
- const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
- Result << Attr.Name;
- if (!Attr.Value.empty())
- Result << "=\"" << Attr.Value << "\"";
- }
- }
- if (!C->isSelfClosing())
- Result << ">";
- else
- Result << "/>";
- }
- class CommentASTToHTMLConverter :
- public ConstCommentVisitor<CommentASTToHTMLConverter> {
- public:
- /// \param Str accumulator for HTML.
- CommentASTToHTMLConverter(const FullComment *FC,
- SmallVectorImpl<char> &Str,
- const CommandTraits &Traits) :
- FC(FC), Result(Str), Traits(Traits)
- { }
- // Inline content.
- void visitTextComment(const TextComment *C);
- void visitInlineCommandComment(const InlineCommandComment *C);
- void visitHTMLStartTagComment(const HTMLStartTagComment *C);
- void visitHTMLEndTagComment(const HTMLEndTagComment *C);
- // Block content.
- void visitParagraphComment(const ParagraphComment *C);
- void visitBlockCommandComment(const BlockCommandComment *C);
- void visitParamCommandComment(const ParamCommandComment *C);
- void visitTParamCommandComment(const TParamCommandComment *C);
- void visitVerbatimBlockComment(const VerbatimBlockComment *C);
- void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
- void visitVerbatimLineComment(const VerbatimLineComment *C);
- void visitFullComment(const FullComment *C);
- // Helpers.
- /// Convert a paragraph that is not a block by itself (an argument to some
- /// command).
- void visitNonStandaloneParagraphComment(const ParagraphComment *C);
- void appendToResultWithHTMLEscaping(StringRef S);
- private:
- const FullComment *FC;
- /// Output stream for HTML.
- llvm::raw_svector_ostream Result;
- const CommandTraits &Traits;
- };
- } // end unnamed namespace
- void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
- appendToResultWithHTMLEscaping(C->getText());
- }
- void CommentASTToHTMLConverter::visitInlineCommandComment(
- const InlineCommandComment *C) {
- // Nothing to render if no arguments supplied.
- if (C->getNumArgs() == 0)
- return;
- // Nothing to render if argument is empty.
- StringRef Arg0 = C->getArgText(0);
- if (Arg0.empty())
- return;
- switch (C->getRenderKind()) {
- case InlineCommandComment::RenderNormal:
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
- appendToResultWithHTMLEscaping(C->getArgText(i));
- Result << " ";
- }
- return;
- case InlineCommandComment::RenderBold:
- assert(C->getNumArgs() == 1);
- Result << "<b>";
- appendToResultWithHTMLEscaping(Arg0);
- Result << "</b>";
- return;
- case InlineCommandComment::RenderMonospaced:
- assert(C->getNumArgs() == 1);
- Result << "<tt>";
- appendToResultWithHTMLEscaping(Arg0);
- Result<< "</tt>";
- return;
- case InlineCommandComment::RenderEmphasized:
- assert(C->getNumArgs() == 1);
- Result << "<em>";
- appendToResultWithHTMLEscaping(Arg0);
- Result << "</em>";
- return;
- case InlineCommandComment::RenderAnchor:
- assert(C->getNumArgs() == 1);
- Result << "<span id=\"" << Arg0 << "\"></span>";
- return;
- }
- }
- void CommentASTToHTMLConverter::visitHTMLStartTagComment(
- const HTMLStartTagComment *C) {
- printHTMLStartTagComment(C, Result);
- }
- void CommentASTToHTMLConverter::visitHTMLEndTagComment(
- const HTMLEndTagComment *C) {
- Result << "</" << C->getTagName() << ">";
- }
- void CommentASTToHTMLConverter::visitParagraphComment(
- const ParagraphComment *C) {
- if (C->isWhitespace())
- return;
- Result << "<p>";
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I) {
- visit(*I);
- }
- Result << "</p>";
- }
- void CommentASTToHTMLConverter::visitBlockCommandComment(
- const BlockCommandComment *C) {
- const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
- if (Info->IsBriefCommand) {
- Result << "<p class=\"para-brief\">";
- visitNonStandaloneParagraphComment(C->getParagraph());
- Result << "</p>";
- return;
- }
- if (Info->IsReturnsCommand) {
- Result << "<p class=\"para-returns\">"
- "<span class=\"word-returns\">Returns</span> ";
- visitNonStandaloneParagraphComment(C->getParagraph());
- Result << "</p>";
- return;
- }
- // We don't know anything about this command. Just render the paragraph.
- visit(C->getParagraph());
- }
- void CommentASTToHTMLConverter::visitParamCommandComment(
- const ParamCommandComment *C) {
- if (C->isParamIndexValid()) {
- if (C->isVarArgParam()) {
- Result << "<dt class=\"param-name-index-vararg\">";
- appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
- } else {
- Result << "<dt class=\"param-name-index-"
- << C->getParamIndex()
- << "\">";
- appendToResultWithHTMLEscaping(C->getParamName(FC));
- }
- } else {
- Result << "<dt class=\"param-name-index-invalid\">";
- appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
- }
- Result << "</dt>";
- if (C->isParamIndexValid()) {
- if (C->isVarArgParam())
- Result << "<dd class=\"param-descr-index-vararg\">";
- else
- Result << "<dd class=\"param-descr-index-"
- << C->getParamIndex()
- << "\">";
- } else
- Result << "<dd class=\"param-descr-index-invalid\">";
- visitNonStandaloneParagraphComment(C->getParagraph());
- Result << "</dd>";
- }
- void CommentASTToHTMLConverter::visitTParamCommandComment(
- const TParamCommandComment *C) {
- if (C->isPositionValid()) {
- if (C->getDepth() == 1)
- Result << "<dt class=\"tparam-name-index-"
- << C->getIndex(0)
- << "\">";
- else
- Result << "<dt class=\"tparam-name-index-other\">";
- appendToResultWithHTMLEscaping(C->getParamName(FC));
- } else {
- Result << "<dt class=\"tparam-name-index-invalid\">";
- appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
- }
- Result << "</dt>";
- if (C->isPositionValid()) {
- if (C->getDepth() == 1)
- Result << "<dd class=\"tparam-descr-index-"
- << C->getIndex(0)
- << "\">";
- else
- Result << "<dd class=\"tparam-descr-index-other\">";
- } else
- Result << "<dd class=\"tparam-descr-index-invalid\">";
- visitNonStandaloneParagraphComment(C->getParagraph());
- Result << "</dd>";
- }
- void CommentASTToHTMLConverter::visitVerbatimBlockComment(
- const VerbatimBlockComment *C) {
- unsigned NumLines = C->getNumLines();
- if (NumLines == 0)
- return;
- Result << "<pre>";
- for (unsigned i = 0; i != NumLines; ++i) {
- appendToResultWithHTMLEscaping(C->getText(i));
- if (i + 1 != NumLines)
- Result << '\n';
- }
- Result << "</pre>";
- }
- void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
- const VerbatimBlockLineComment *C) {
- llvm_unreachable("should not see this AST node");
- }
- void CommentASTToHTMLConverter::visitVerbatimLineComment(
- const VerbatimLineComment *C) {
- Result << "<pre>";
- appendToResultWithHTMLEscaping(C->getText());
- Result << "</pre>";
- }
- void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
- FullCommentParts Parts(C, Traits);
- bool FirstParagraphIsBrief = false;
- if (Parts.Headerfile)
- visit(Parts.Headerfile);
- if (Parts.Brief)
- visit(Parts.Brief);
- else if (Parts.FirstParagraph) {
- Result << "<p class=\"para-brief\">";
- visitNonStandaloneParagraphComment(Parts.FirstParagraph);
- Result << "</p>";
- FirstParagraphIsBrief = true;
- }
- for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
- const Comment *C = Parts.MiscBlocks[i];
- if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
- continue;
- visit(C);
- }
- if (Parts.TParams.size() != 0) {
- Result << "<dl>";
- for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
- visit(Parts.TParams[i]);
- Result << "</dl>";
- }
- if (Parts.Params.size() != 0) {
- Result << "<dl>";
- for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
- visit(Parts.Params[i]);
- Result << "</dl>";
- }
- if (Parts.Returns.size() != 0) {
- Result << "<div class=\"result-discussion\">";
- for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
- visit(Parts.Returns[i]);
- Result << "</div>";
- }
- }
- void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
- const ParagraphComment *C) {
- if (!C)
- return;
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I) {
- visit(*I);
- }
- }
- void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
- for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
- const char C = *I;
- switch (C) {
- case '&':
- Result << "&";
- break;
- case '<':
- Result << "<";
- break;
- case '>':
- Result << ">";
- break;
- case '"':
- Result << """;
- break;
- case '\'':
- Result << "'";
- break;
- case '/':
- Result << "/";
- break;
- default:
- Result << C;
- break;
- }
- }
- }
- namespace {
- class CommentASTToXMLConverter :
- public ConstCommentVisitor<CommentASTToXMLConverter> {
- public:
- /// \param Str accumulator for XML.
- CommentASTToXMLConverter(const FullComment *FC,
- SmallVectorImpl<char> &Str,
- const CommandTraits &Traits,
- const SourceManager &SM) :
- FC(FC), Result(Str), Traits(Traits), SM(SM) { }
- // Inline content.
- void visitTextComment(const TextComment *C);
- void visitInlineCommandComment(const InlineCommandComment *C);
- void visitHTMLStartTagComment(const HTMLStartTagComment *C);
- void visitHTMLEndTagComment(const HTMLEndTagComment *C);
- // Block content.
- void visitParagraphComment(const ParagraphComment *C);
- void appendParagraphCommentWithKind(const ParagraphComment *C,
- StringRef Kind);
- void visitBlockCommandComment(const BlockCommandComment *C);
- void visitParamCommandComment(const ParamCommandComment *C);
- void visitTParamCommandComment(const TParamCommandComment *C);
- void visitVerbatimBlockComment(const VerbatimBlockComment *C);
- void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
- void visitVerbatimLineComment(const VerbatimLineComment *C);
- void visitFullComment(const FullComment *C);
- // Helpers.
- void appendToResultWithXMLEscaping(StringRef S);
- void appendToResultWithCDATAEscaping(StringRef S);
- void formatTextOfDeclaration(const DeclInfo *DI,
- SmallString<128> &Declaration);
- private:
- const FullComment *FC;
- /// Output stream for XML.
- llvm::raw_svector_ostream Result;
- const CommandTraits &Traits;
- const SourceManager &SM;
- };
- void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
- SmallVectorImpl<char> &Str) {
- ASTContext &Context = ThisDecl->CurrentDecl->getASTContext();
- const LangOptions &LangOpts = Context.getLangOpts();
- llvm::raw_svector_ostream OS(Str);
- PrintingPolicy PPolicy(LangOpts);
- PPolicy.PolishForDeclaration = true;
- PPolicy.TerseOutput = true;
- PPolicy.ConstantsAsWritten = true;
- ThisDecl->CurrentDecl->print(OS, PPolicy,
- /*Indentation*/0, /*PrintInstantiation*/false);
- }
- void CommentASTToXMLConverter::formatTextOfDeclaration(
- const DeclInfo *DI, SmallString<128> &Declaration) {
- // Formatting API expects null terminated input string.
- StringRef StringDecl(Declaration.c_str(), Declaration.size());
- // Formatter specific code.
- unsigned Offset = 0;
- unsigned Length = Declaration.size();
- format::FormatStyle Style = format::getLLVMStyle();
- Style.FixNamespaceComments = false;
- tooling::Replacements Replaces =
- reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd");
- auto FormattedStringDecl = applyAllReplacements(StringDecl, Replaces);
- if (static_cast<bool>(FormattedStringDecl)) {
- Declaration = *FormattedStringDecl;
- }
- }
- } // end unnamed namespace
- void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
- appendToResultWithXMLEscaping(C->getText());
- }
- void CommentASTToXMLConverter::visitInlineCommandComment(
- const InlineCommandComment *C) {
- // Nothing to render if no arguments supplied.
- if (C->getNumArgs() == 0)
- return;
- // Nothing to render if argument is empty.
- StringRef Arg0 = C->getArgText(0);
- if (Arg0.empty())
- return;
- switch (C->getRenderKind()) {
- case InlineCommandComment::RenderNormal:
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
- appendToResultWithXMLEscaping(C->getArgText(i));
- Result << " ";
- }
- return;
- case InlineCommandComment::RenderBold:
- assert(C->getNumArgs() == 1);
- Result << "<bold>";
- appendToResultWithXMLEscaping(Arg0);
- Result << "</bold>";
- return;
- case InlineCommandComment::RenderMonospaced:
- assert(C->getNumArgs() == 1);
- Result << "<monospaced>";
- appendToResultWithXMLEscaping(Arg0);
- Result << "</monospaced>";
- return;
- case InlineCommandComment::RenderEmphasized:
- assert(C->getNumArgs() == 1);
- Result << "<emphasized>";
- appendToResultWithXMLEscaping(Arg0);
- Result << "</emphasized>";
- return;
- case InlineCommandComment::RenderAnchor:
- assert(C->getNumArgs() == 1);
- Result << "<anchor id=\"" << Arg0 << "\"></anchor>";
- return;
- }
- }
- void CommentASTToXMLConverter::visitHTMLStartTagComment(
- const HTMLStartTagComment *C) {
- Result << "<rawHTML";
- if (C->isMalformed())
- Result << " isMalformed=\"1\"";
- Result << ">";
- {
- SmallString<32> Tag;
- {
- llvm::raw_svector_ostream TagOS(Tag);
- printHTMLStartTagComment(C, TagOS);
- }
- appendToResultWithCDATAEscaping(Tag);
- }
- Result << "</rawHTML>";
- }
- void
- CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
- Result << "<rawHTML";
- if (C->isMalformed())
- Result << " isMalformed=\"1\"";
- Result << "></" << C->getTagName() << "></rawHTML>";
- }
- void
- CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
- appendParagraphCommentWithKind(C, StringRef());
- }
- void CommentASTToXMLConverter::appendParagraphCommentWithKind(
- const ParagraphComment *C,
- StringRef ParagraphKind) {
- if (C->isWhitespace())
- return;
- if (ParagraphKind.empty())
- Result << "<Para>";
- else
- Result << "<Para kind=\"" << ParagraphKind << "\">";
- for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
- I != E; ++I) {
- visit(*I);
- }
- Result << "</Para>";
- }
- void CommentASTToXMLConverter::visitBlockCommandComment(
- const BlockCommandComment *C) {
- StringRef ParagraphKind;
- switch (C->getCommandID()) {
- case CommandTraits::KCI_attention:
- case CommandTraits::KCI_author:
- case CommandTraits::KCI_authors:
- case CommandTraits::KCI_bug:
- case CommandTraits::KCI_copyright:
- case CommandTraits::KCI_date:
- case CommandTraits::KCI_invariant:
- case CommandTraits::KCI_note:
- case CommandTraits::KCI_post:
- case CommandTraits::KCI_pre:
- case CommandTraits::KCI_remark:
- case CommandTraits::KCI_remarks:
- case CommandTraits::KCI_sa:
- case CommandTraits::KCI_see:
- case CommandTraits::KCI_since:
- case CommandTraits::KCI_todo:
- case CommandTraits::KCI_version:
- case CommandTraits::KCI_warning:
- ParagraphKind = C->getCommandName(Traits);
- break;
- default:
- break;
- }
- appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind);
- }
- void CommentASTToXMLConverter::visitParamCommandComment(
- const ParamCommandComment *C) {
- Result << "<Parameter><Name>";
- appendToResultWithXMLEscaping(C->isParamIndexValid()
- ? C->getParamName(FC)
- : C->getParamNameAsWritten());
- Result << "</Name>";
- if (C->isParamIndexValid()) {
- if (C->isVarArgParam())
- Result << "<IsVarArg />";
- else
- Result << "<Index>" << C->getParamIndex() << "</Index>";
- }
- Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">";
- switch (C->getDirection()) {
- case ParamCommandComment::In:
- Result << "in";
- break;
- case ParamCommandComment::Out:
- Result << "out";
- break;
- case ParamCommandComment::InOut:
- Result << "in,out";
- break;
- }
- Result << "</Direction><Discussion>";
- visit(C->getParagraph());
- Result << "</Discussion></Parameter>";
- }
- void CommentASTToXMLConverter::visitTParamCommandComment(
- const TParamCommandComment *C) {
- Result << "<Parameter><Name>";
- appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
- : C->getParamNameAsWritten());
- Result << "</Name>";
- if (C->isPositionValid() && C->getDepth() == 1) {
- Result << "<Index>" << C->getIndex(0) << "</Index>";
- }
- Result << "<Discussion>";
- visit(C->getParagraph());
- Result << "</Discussion></Parameter>";
- }
- void CommentASTToXMLConverter::visitVerbatimBlockComment(
- const VerbatimBlockComment *C) {
- unsigned NumLines = C->getNumLines();
- if (NumLines == 0)
- return;
- switch (C->getCommandID()) {
- case CommandTraits::KCI_code:
- Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">";
- break;
- default:
- Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
- break;
- }
- for (unsigned i = 0; i != NumLines; ++i) {
- appendToResultWithXMLEscaping(C->getText(i));
- if (i + 1 != NumLines)
- Result << '\n';
- }
- Result << "</Verbatim>";
- }
- void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
- const VerbatimBlockLineComment *C) {
- llvm_unreachable("should not see this AST node");
- }
- void CommentASTToXMLConverter::visitVerbatimLineComment(
- const VerbatimLineComment *C) {
- Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
- appendToResultWithXMLEscaping(C->getText());
- Result << "</Verbatim>";
- }
- void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
- FullCommentParts Parts(C, Traits);
- const DeclInfo *DI = C->getDeclInfo();
- StringRef RootEndTag;
- if (DI) {
- switch (DI->getKind()) {
- case DeclInfo::OtherKind:
- RootEndTag = "</Other>";
- Result << "<Other";
- break;
- case DeclInfo::FunctionKind:
- RootEndTag = "</Function>";
- Result << "<Function";
- switch (DI->TemplateKind) {
- case DeclInfo::NotTemplate:
- break;
- case DeclInfo::Template:
- Result << " templateKind=\"template\"";
- break;
- case DeclInfo::TemplateSpecialization:
- Result << " templateKind=\"specialization\"";
- break;
- case DeclInfo::TemplatePartialSpecialization:
- llvm_unreachable("partial specializations of functions "
- "are not allowed in C++");
- }
- if (DI->IsInstanceMethod)
- Result << " isInstanceMethod=\"1\"";
- if (DI->IsClassMethod)
- Result << " isClassMethod=\"1\"";
- break;
- case DeclInfo::ClassKind:
- RootEndTag = "</Class>";
- Result << "<Class";
- switch (DI->TemplateKind) {
- case DeclInfo::NotTemplate:
- break;
- case DeclInfo::Template:
- Result << " templateKind=\"template\"";
- break;
- case DeclInfo::TemplateSpecialization:
- Result << " templateKind=\"specialization\"";
- break;
- case DeclInfo::TemplatePartialSpecialization:
- Result << " templateKind=\"partialSpecialization\"";
- break;
- }
- break;
- case DeclInfo::VariableKind:
- RootEndTag = "</Variable>";
- Result << "<Variable";
- break;
- case DeclInfo::NamespaceKind:
- RootEndTag = "</Namespace>";
- Result << "<Namespace";
- break;
- case DeclInfo::TypedefKind:
- RootEndTag = "</Typedef>";
- Result << "<Typedef";
- break;
- case DeclInfo::EnumKind:
- RootEndTag = "</Enum>";
- Result << "<Enum";
- break;
- }
- {
- // Print line and column number.
- SourceLocation Loc = DI->CurrentDecl->getLocation();
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
- FileID FID = LocInfo.first;
- unsigned FileOffset = LocInfo.second;
- if (FID.isValid()) {
- if (const FileEntry *FE = SM.getFileEntryForID(FID)) {
- Result << " file=\"";
- appendToResultWithXMLEscaping(FE->getName());
- Result << "\"";
- }
- Result << " line=\"" << SM.getLineNumber(FID, FileOffset)
- << "\" column=\"" << SM.getColumnNumber(FID, FileOffset)
- << "\"";
- }
- }
- // Finish the root tag.
- Result << ">";
- bool FoundName = false;
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
- if (DeclarationName DeclName = ND->getDeclName()) {
- Result << "<Name>";
- std::string Name = DeclName.getAsString();
- appendToResultWithXMLEscaping(Name);
- FoundName = true;
- Result << "</Name>";
- }
- }
- if (!FoundName)
- Result << "<Name><anonymous></Name>";
- {
- // Print USR.
- SmallString<128> USR;
- generateUSRForDecl(DI->CommentDecl, USR);
- if (!USR.empty()) {
- Result << "<USR>";
- appendToResultWithXMLEscaping(USR);
- Result << "</USR>";
- }
- }
- } else {
- // No DeclInfo -- just emit some root tag and name tag.
- RootEndTag = "</Other>";
- Result << "<Other><Name>unknown</Name>";
- }
- if (Parts.Headerfile) {
- Result << "<Headerfile>";
- visit(Parts.Headerfile);
- Result << "</Headerfile>";
- }
- {
- // Pretty-print the declaration.
- Result << "<Declaration>";
- SmallString<128> Declaration;
- getSourceTextOfDeclaration(DI, Declaration);
- formatTextOfDeclaration(DI, Declaration);
- appendToResultWithXMLEscaping(Declaration);
- Result << "</Declaration>";
- }
- bool FirstParagraphIsBrief = false;
- if (Parts.Brief) {
- Result << "<Abstract>";
- visit(Parts.Brief);
- Result << "</Abstract>";
- } else if (Parts.FirstParagraph) {
- Result << "<Abstract>";
- visit(Parts.FirstParagraph);
- Result << "</Abstract>";
- FirstParagraphIsBrief = true;
- }
- if (Parts.TParams.size() != 0) {
- Result << "<TemplateParameters>";
- for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
- visit(Parts.TParams[i]);
- Result << "</TemplateParameters>";
- }
- if (Parts.Params.size() != 0) {
- Result << "<Parameters>";
- for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
- visit(Parts.Params[i]);
- Result << "</Parameters>";
- }
- if (Parts.Exceptions.size() != 0) {
- Result << "<Exceptions>";
- for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
- visit(Parts.Exceptions[i]);
- Result << "</Exceptions>";
- }
- if (Parts.Returns.size() != 0) {
- Result << "<ResultDiscussion>";
- for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
- visit(Parts.Returns[i]);
- Result << "</ResultDiscussion>";
- }
- if (DI->CommentDecl->hasAttrs()) {
- const AttrVec &Attrs = DI->CommentDecl->getAttrs();
- for (unsigned i = 0, e = Attrs.size(); i != e; i++) {
- const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
- if (!AA) {
- if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
- if (DA->getMessage().empty())
- Result << "<Deprecated/>";
- else {
- Result << "<Deprecated>";
- appendToResultWithXMLEscaping(DA->getMessage());
- Result << "</Deprecated>";
- }
- }
- else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
- if (UA->getMessage().empty())
- Result << "<Unavailable/>";
- else {
- Result << "<Unavailable>";
- appendToResultWithXMLEscaping(UA->getMessage());
- Result << "</Unavailable>";
- }
- }
- continue;
- }
- // 'availability' attribute.
- Result << "<Availability";
- StringRef Distribution;
- if (AA->getPlatform()) {
- Distribution = AvailabilityAttr::getPrettyPlatformName(
- AA->getPlatform()->getName());
- if (Distribution.empty())
- Distribution = AA->getPlatform()->getName();
- }
- Result << " distribution=\"" << Distribution << "\">";
- VersionTuple IntroducedInVersion = AA->getIntroduced();
- if (!IntroducedInVersion.empty()) {
- Result << "<IntroducedInVersion>"
- << IntroducedInVersion.getAsString()
- << "</IntroducedInVersion>";
- }
- VersionTuple DeprecatedInVersion = AA->getDeprecated();
- if (!DeprecatedInVersion.empty()) {
- Result << "<DeprecatedInVersion>"
- << DeprecatedInVersion.getAsString()
- << "</DeprecatedInVersion>";
- }
- VersionTuple RemovedAfterVersion = AA->getObsoleted();
- if (!RemovedAfterVersion.empty()) {
- Result << "<RemovedAfterVersion>"
- << RemovedAfterVersion.getAsString()
- << "</RemovedAfterVersion>";
- }
- StringRef DeprecationSummary = AA->getMessage();
- if (!DeprecationSummary.empty()) {
- Result << "<DeprecationSummary>";
- appendToResultWithXMLEscaping(DeprecationSummary);
- Result << "</DeprecationSummary>";
- }
- if (AA->getUnavailable())
- Result << "<Unavailable/>";
- Result << "</Availability>";
- }
- }
- {
- bool StartTagEmitted = false;
- for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
- const Comment *C = Parts.MiscBlocks[i];
- if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
- continue;
- if (!StartTagEmitted) {
- Result << "<Discussion>";
- StartTagEmitted = true;
- }
- visit(C);
- }
- if (StartTagEmitted)
- Result << "</Discussion>";
- }
- Result << RootEndTag;
- }
- void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
- for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
- const char C = *I;
- switch (C) {
- case '&':
- Result << "&";
- break;
- case '<':
- Result << "<";
- break;
- case '>':
- Result << ">";
- break;
- case '"':
- Result << """;
- break;
- case '\'':
- Result << "'";
- break;
- default:
- Result << C;
- break;
- }
- }
- }
- void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
- if (S.empty())
- return;
- Result << "<![CDATA[";
- while (!S.empty()) {
- size_t Pos = S.find("]]>");
- if (Pos == 0) {
- Result << "]]]]><![CDATA[>";
- S = S.drop_front(3);
- continue;
- }
- if (Pos == StringRef::npos)
- Pos = S.size();
- Result << S.substr(0, Pos);
- S = S.drop_front(Pos);
- }
- Result << "]]>";
- }
- CommentToXMLConverter::CommentToXMLConverter() {}
- CommentToXMLConverter::~CommentToXMLConverter() {}
- void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC,
- SmallVectorImpl<char> &HTML,
- const ASTContext &Context) {
- CommentASTToHTMLConverter Converter(FC, HTML,
- Context.getCommentCommandTraits());
- Converter.visit(FC);
- }
- void CommentToXMLConverter::convertHTMLTagNodeToText(
- const comments::HTMLTagComment *HTC, SmallVectorImpl<char> &Text,
- const ASTContext &Context) {
- CommentASTToHTMLConverter Converter(nullptr, Text,
- Context.getCommentCommandTraits());
- Converter.visit(HTC);
- }
- void CommentToXMLConverter::convertCommentToXML(const FullComment *FC,
- SmallVectorImpl<char> &XML,
- const ASTContext &Context) {
- CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(),
- Context.getSourceManager());
- Converter.visit(FC);
- }
|