1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162 |
- //===--- CommentToXML.cpp - Convert comments to XML representation --------===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Index/CommentToXML.h"
- #include "SimpleFormatContext.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/Attr.h"
- #include "clang/AST/Comment.h"
- #include "clang/AST/CommentVisitor.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.
- std::stable_sort(Params.begin(), Params.end(),
- ParamCommandCommentCompareIndex());
- std::stable_sort(TParams.begin(), TParams.end(),
- 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;
- }
- }
- 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,
- SimpleFormatContext &SFC,
- unsigned FUID) :
- FC(FC), Result(Str), Traits(Traits), SM(SM),
- FormatRewriterContext(SFC),
- FormatInMemoryUniqueId(FUID) { }
- // 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;
- SimpleFormatContext &FormatRewriterContext;
- unsigned FormatInMemoryUniqueId;
- };
- 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;
- 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.
- // Form a unique in memory buffer name.
- SmallString<128> Filename;
- Filename += "xmldecl";
- Filename += llvm::utostr(FormatInMemoryUniqueId);
- Filename += ".xd";
- unsigned Offset = 0;
- unsigned Length = Declaration.size();
- bool IncompleteFormat = false;
- tooling::Replacements Replaces =
- reformat(format::getLLVMStyle(), StringDecl,
- tooling::Range(Offset, Length), Filename, &IncompleteFormat);
- 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;
- }
- }
- 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);
- 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() : FormatInMemoryUniqueId(0) {}
- 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) {
- if (!FormatContext || (FormatInMemoryUniqueId % 1000) == 0) {
- // Create a new format context, or re-create it after some number of
- // iterations, so the buffers don't grow too large.
- FormatContext.reset(new SimpleFormatContext(Context.getLangOpts()));
- }
- CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(),
- Context.getSourceManager(), *FormatContext,
- FormatInMemoryUniqueId++);
- Converter.visit(FC);
- }
|