18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/TinyPtrVector.h"
20#include "llvm/Support/raw_ostream.h"
30class ParamCommandCommentCompareIndex {
49 return LHSIndex < RHSIndex;
57class TParamCommandCommentComparePosition {
82struct FullCommentParts {
93 llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
99 Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
105 switch (Child->getCommentKind()) {
106 case CommentKind::None:
109 case CommentKind::ParagraphComment: {
116 MiscBlocks.push_back(PC);
120 case CommentKind::BlockCommandComment: {
132 Returns.push_back(BCC);
136 Exceptions.push_back(BCC);
139 MiscBlocks.push_back(BCC);
143 case CommentKind::ParamCommandComment: {
151 Params.push_back(PCC);
155 case CommentKind::TParamCommandComment: {
163 TParams.push_back(TPCC);
167 case CommentKind::VerbatimBlockComment:
168 MiscBlocks.push_back(cast<BlockCommandComment>(Child));
171 case CommentKind::VerbatimLineComment: {
175 MiscBlocks.push_back(VLC);
179 case CommentKind::TextComment:
180 case CommentKind::InlineCommandComment:
181 case CommentKind::HTMLStartTagComment:
182 case CommentKind::HTMLEndTagComment:
183 case CommentKind::VerbatimBlockLineComment:
184 case CommentKind::FullComment:
185 llvm_unreachable(
"AST node of this kind can't be a child of "
193 llvm::stable_sort(Params, ParamCommandCommentCompareIndex());
194 llvm::stable_sort(TParams, TParamCommandCommentComparePosition());
198 llvm::raw_svector_ostream &Result) {
199 Result <<
"<" <<
C->getTagName();
201 if (
C->getNumAttrs() != 0) {
202 for (
unsigned i = 0, e =
C->getNumAttrs(); i != e; i++) {
206 if (!
Attr.Value.empty())
207 Result <<
"=\"" <<
Attr.Value <<
"\"";
211 if (!
C->isSelfClosing())
217class CommentASTToHTMLConverter :
224 FC(FC), Result(Str), Traits(Traits)
250 void appendToResultWithHTMLEscaping(StringRef S);
255 llvm::raw_svector_ostream
Result;
261void CommentASTToHTMLConverter::visitTextComment(
const TextComment *
C) {
262 appendToResultWithHTMLEscaping(
C->getText());
265void CommentASTToHTMLConverter::visitInlineCommandComment(
268 if (
C->getNumArgs() == 0)
272 StringRef Arg0 =
C->getArgText(0);
276 switch (
C->getRenderKind()) {
277 case InlineCommandRenderKind::Normal:
278 for (
unsigned i = 0, e =
C->getNumArgs(); i != e; ++i) {
279 appendToResultWithHTMLEscaping(
C->getArgText(i));
284 case InlineCommandRenderKind::Bold:
285 assert(
C->getNumArgs() == 1);
287 appendToResultWithHTMLEscaping(Arg0);
290 case InlineCommandRenderKind::Monospaced:
291 assert(
C->getNumArgs() == 1);
293 appendToResultWithHTMLEscaping(Arg0);
296 case InlineCommandRenderKind::Emphasized:
297 assert(
C->getNumArgs() == 1);
299 appendToResultWithHTMLEscaping(Arg0);
302 case InlineCommandRenderKind::Anchor:
303 assert(
C->getNumArgs() == 1);
304 Result <<
"<span id=\"" << Arg0 <<
"\"></span>";
309void CommentASTToHTMLConverter::visitHTMLStartTagComment(
311 printHTMLStartTagComment(
C, Result);
314void CommentASTToHTMLConverter::visitHTMLEndTagComment(
316 Result <<
"</" <<
C->getTagName() <<
">";
319void CommentASTToHTMLConverter::visitParagraphComment(
321 if (
C->isWhitespace())
332void CommentASTToHTMLConverter::visitBlockCommandComment(
336 Result <<
"<p class=\"para-brief\">";
337 visitNonStandaloneParagraphComment(
C->getParagraph());
342 Result <<
"<p class=\"para-returns\">"
343 "<span class=\"word-returns\">Returns</span> ";
344 visitNonStandaloneParagraphComment(
C->getParagraph());
349 visit(
C->getParagraph());
352void CommentASTToHTMLConverter::visitParamCommandComment(
354 if (
C->isParamIndexValid()) {
355 if (
C->isVarArgParam()) {
356 Result <<
"<dt class=\"param-name-index-vararg\">";
357 appendToResultWithHTMLEscaping(
C->getParamNameAsWritten());
359 Result <<
"<dt class=\"param-name-index-"
360 <<
C->getParamIndex()
362 appendToResultWithHTMLEscaping(
C->getParamName(FC));
365 Result <<
"<dt class=\"param-name-index-invalid\">";
366 appendToResultWithHTMLEscaping(
C->getParamNameAsWritten());
370 if (
C->isParamIndexValid()) {
371 if (
C->isVarArgParam())
372 Result <<
"<dd class=\"param-descr-index-vararg\">";
374 Result <<
"<dd class=\"param-descr-index-"
375 <<
C->getParamIndex()
378 Result <<
"<dd class=\"param-descr-index-invalid\">";
380 visitNonStandaloneParagraphComment(
C->getParagraph());
384void CommentASTToHTMLConverter::visitTParamCommandComment(
386 if (
C->isPositionValid()) {
387 if (
C->getDepth() == 1)
388 Result <<
"<dt class=\"tparam-name-index-"
392 Result <<
"<dt class=\"tparam-name-index-other\">";
393 appendToResultWithHTMLEscaping(
C->getParamName(FC));
395 Result <<
"<dt class=\"tparam-name-index-invalid\">";
396 appendToResultWithHTMLEscaping(
C->getParamNameAsWritten());
401 if (
C->isPositionValid()) {
402 if (
C->getDepth() == 1)
403 Result <<
"<dd class=\"tparam-descr-index-"
407 Result <<
"<dd class=\"tparam-descr-index-other\">";
409 Result <<
"<dd class=\"tparam-descr-index-invalid\">";
411 visitNonStandaloneParagraphComment(
C->getParagraph());
415void CommentASTToHTMLConverter::visitVerbatimBlockComment(
417 unsigned NumLines =
C->getNumLines();
422 for (
unsigned i = 0; i != NumLines; ++i) {
423 appendToResultWithHTMLEscaping(
C->getText(i));
424 if (i + 1 != NumLines)
430void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
432 llvm_unreachable(
"should not see this AST node");
435void CommentASTToHTMLConverter::visitVerbatimLineComment(
438 appendToResultWithHTMLEscaping(
C->getText());
442void CommentASTToHTMLConverter::visitFullComment(
const FullComment *
C) {
443 FullCommentParts Parts(
C, Traits);
445 bool FirstParagraphIsBrief =
false;
446 if (Parts.Headerfile)
447 visit(Parts.Headerfile);
450 else if (Parts.FirstParagraph) {
451 Result <<
"<p class=\"para-brief\">";
452 visitNonStandaloneParagraphComment(Parts.FirstParagraph);
454 FirstParagraphIsBrief =
true;
457 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
458 const Comment *
C = Parts.MiscBlocks[i];
459 if (FirstParagraphIsBrief &&
C == Parts.FirstParagraph)
464 if (Parts.TParams.size() != 0) {
466 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
467 visit(Parts.TParams[i]);
471 if (Parts.Params.size() != 0) {
473 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
474 visit(Parts.Params[i]);
478 if (Parts.Returns.size() != 0) {
479 Result <<
"<div class=\"result-discussion\">";
480 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
481 visit(Parts.Returns[i]);
487void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
498void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
499 for (StringRef::iterator I = S.begin(),
E = S.end(); I !=
E; ++I) {
528class CommentASTToXMLConverter :
536 FC(FC), Result(Str), Traits(Traits),
SM(
SM) { }
548 StringRef ParagraphKind,
549 StringRef PrependBodyText);
561 void appendToResultWithXMLEscaping(StringRef S);
562 void appendToResultWithCDATAEscaping(StringRef S);
564 void formatTextOfDeclaration(
const DeclInfo *DI,
571 llvm::raw_svector_ostream
Result;
577void getSourceTextOfDeclaration(
const DeclInfo *ThisDecl,
581 llvm::raw_svector_ostream OS(Str);
583 PPolicy.PolishForDeclaration =
true;
584 PPolicy.TerseOutput =
true;
585 PPolicy.ConstantsAsWritten =
true;
590void CommentASTToXMLConverter::formatTextOfDeclaration(
600 Style.FixNamespaceComments =
false;
604 if (
static_cast<bool>(FormattedStringDecl)) {
611void CommentASTToXMLConverter::visitTextComment(
const TextComment *
C) {
612 appendToResultWithXMLEscaping(
C->getText());
615void CommentASTToXMLConverter::visitInlineCommandComment(
618 if (
C->getNumArgs() == 0)
622 StringRef Arg0 =
C->getArgText(0);
626 switch (
C->getRenderKind()) {
627 case InlineCommandRenderKind::Normal:
628 for (
unsigned i = 0, e =
C->getNumArgs(); i != e; ++i) {
629 appendToResultWithXMLEscaping(
C->getArgText(i));
633 case InlineCommandRenderKind::Bold:
634 assert(
C->getNumArgs() == 1);
636 appendToResultWithXMLEscaping(Arg0);
639 case InlineCommandRenderKind::Monospaced:
640 assert(
C->getNumArgs() == 1);
641 Result <<
"<monospaced>";
642 appendToResultWithXMLEscaping(Arg0);
643 Result <<
"</monospaced>";
645 case InlineCommandRenderKind::Emphasized:
646 assert(
C->getNumArgs() == 1);
647 Result <<
"<emphasized>";
648 appendToResultWithXMLEscaping(Arg0);
649 Result <<
"</emphasized>";
651 case InlineCommandRenderKind::Anchor:
652 assert(
C->getNumArgs() == 1);
653 Result <<
"<anchor id=\"" << Arg0 <<
"\"></anchor>";
658void CommentASTToXMLConverter::visitHTMLStartTagComment(
660 Result <<
"<rawHTML";
661 if (
C->isMalformed())
662 Result <<
" isMalformed=\"1\"";
667 llvm::raw_svector_ostream TagOS(Tag);
668 printHTMLStartTagComment(
C, TagOS);
670 appendToResultWithCDATAEscaping(Tag);
672 Result <<
"</rawHTML>";
677 Result <<
"<rawHTML";
678 if (
C->isMalformed())
679 Result <<
" isMalformed=\"1\"";
680 Result <<
"></" <<
C->getTagName() <<
"></rawHTML>";
683void CommentASTToXMLConverter::visitParagraphComment(
685 appendParagraphCommentWithKind(
C, StringRef(), StringRef());
688void CommentASTToXMLConverter::appendParagraphCommentWithKind(
690 StringRef PrependBodyText) {
691 if (
C->isWhitespace() && PrependBodyText.empty())
694 if (ParagraphKind.empty())
697 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
699 if (!PrependBodyText.empty())
700 Result << PrependBodyText <<
" ";
709void CommentASTToXMLConverter::visitBlockCommandComment(
711 StringRef ParagraphKind;
712 StringRef ExceptionType;
714 const unsigned CommandID =
C->getCommandID();
717 ExceptionType =
C->getArgText(0);
721 case CommandTraits::KCI_attention:
722 case CommandTraits::KCI_author:
723 case CommandTraits::KCI_authors:
724 case CommandTraits::KCI_bug:
725 case CommandTraits::KCI_copyright:
726 case CommandTraits::KCI_date:
727 case CommandTraits::KCI_invariant:
728 case CommandTraits::KCI_note:
729 case CommandTraits::KCI_post:
730 case CommandTraits::KCI_pre:
731 case CommandTraits::KCI_remark:
732 case CommandTraits::KCI_remarks:
733 case CommandTraits::KCI_sa:
734 case CommandTraits::KCI_see:
735 case CommandTraits::KCI_since:
736 case CommandTraits::KCI_todo:
737 case CommandTraits::KCI_version:
738 case CommandTraits::KCI_warning:
739 ParagraphKind =
C->getCommandName(Traits);
745 appendParagraphCommentWithKind(
C->getParagraph(), ParagraphKind,
749void CommentASTToXMLConverter::visitParamCommandComment(
751 Result <<
"<Parameter><Name>";
752 appendToResultWithXMLEscaping(
C->isParamIndexValid()
753 ?
C->getParamName(FC)
754 :
C->getParamNameAsWritten());
757 if (
C->isParamIndexValid()) {
758 if (
C->isVarArgParam())
759 Result <<
"<IsVarArg />";
761 Result <<
"<Index>" <<
C->getParamIndex() <<
"</Index>";
764 Result <<
"<Direction isExplicit=\"" <<
C->isDirectionExplicit() <<
"\">";
765 switch (
C->getDirection()) {
766 case ParamCommandPassDirection::In:
769 case ParamCommandPassDirection::Out:
772 case ParamCommandPassDirection::InOut:
776 Result <<
"</Direction><Discussion>";
777 visit(
C->getParagraph());
778 Result <<
"</Discussion></Parameter>";
781void CommentASTToXMLConverter::visitTParamCommandComment(
783 Result <<
"<Parameter><Name>";
784 appendToResultWithXMLEscaping(
C->isPositionValid() ?
C->getParamName(FC)
785 :
C->getParamNameAsWritten());
788 if (
C->isPositionValid() &&
C->getDepth() == 1) {
789 Result <<
"<Index>" <<
C->getIndex(0) <<
"</Index>";
792 Result <<
"<Discussion>";
793 visit(
C->getParagraph());
794 Result <<
"</Discussion></Parameter>";
797void CommentASTToXMLConverter::visitVerbatimBlockComment(
799 unsigned NumLines =
C->getNumLines();
803 switch (
C->getCommandID()) {
804 case CommandTraits::KCI_code:
805 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
808 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
811 for (
unsigned i = 0; i != NumLines; ++i) {
812 appendToResultWithXMLEscaping(
C->getText(i));
813 if (i + 1 != NumLines)
816 Result <<
"</Verbatim>";
819void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
821 llvm_unreachable(
"should not see this AST node");
824void CommentASTToXMLConverter::visitVerbatimLineComment(
826 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
827 appendToResultWithXMLEscaping(
C->getText());
828 Result <<
"</Verbatim>";
831void CommentASTToXMLConverter::visitFullComment(
const FullComment *
C) {
832 FullCommentParts Parts(
C, Traits);
835 StringRef RootEndTag;
839 RootEndTag =
"</Other>";
843 RootEndTag =
"</Function>";
844 Result <<
"<Function";
849 Result <<
" templateKind=\"template\"";
852 Result <<
" templateKind=\"specialization\"";
855 llvm_unreachable(
"partial specializations of functions "
856 "are not allowed in C++");
859 Result <<
" isInstanceMethod=\"1\"";
861 Result <<
" isClassMethod=\"1\"";
864 RootEndTag =
"</Class>";
870 Result <<
" templateKind=\"template\"";
873 Result <<
" templateKind=\"specialization\"";
876 Result <<
" templateKind=\"partialSpecialization\"";
881 RootEndTag =
"</Variable>";
882 Result <<
"<Variable";
885 RootEndTag =
"</Namespace>";
886 Result <<
"<Namespace";
889 RootEndTag =
"</Typedef>";
890 Result <<
"<Typedef";
893 RootEndTag =
"</Enum>";
902 FileID FID = LocInfo.first;
903 unsigned FileOffset = LocInfo.second;
907 Result <<
" file=\"";
908 appendToResultWithXMLEscaping(FE->getName());
911 Result <<
" line=\"" <<
SM.getLineNumber(FID, FileOffset)
912 <<
"\" column=\"" <<
SM.getColumnNumber(FID, FileOffset)
920 bool FoundName =
false;
924 std::string Name = DeclName.getAsString();
925 appendToResultWithXMLEscaping(Name);
931 Result <<
"<Name><anonymous></Name>";
939 appendToResultWithXMLEscaping(USR);
945 RootEndTag =
"</Other>";
946 Result <<
"<Other><Name>unknown</Name>";
949 if (Parts.Headerfile) {
950 Result <<
"<Headerfile>";
951 visit(Parts.Headerfile);
952 Result <<
"</Headerfile>";
957 Result <<
"<Declaration>";
962 Result <<
"</Declaration>";
965 bool FirstParagraphIsBrief =
false;
967 Result <<
"<Abstract>";
969 Result <<
"</Abstract>";
970 }
else if (Parts.FirstParagraph) {
971 Result <<
"<Abstract>";
972 visit(Parts.FirstParagraph);
973 Result <<
"</Abstract>";
974 FirstParagraphIsBrief =
true;
977 if (Parts.TParams.size() != 0) {
978 Result <<
"<TemplateParameters>";
979 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
980 visit(Parts.TParams[i]);
981 Result <<
"</TemplateParameters>";
984 if (Parts.Params.size() != 0) {
985 Result <<
"<Parameters>";
986 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
987 visit(Parts.Params[i]);
988 Result <<
"</Parameters>";
991 if (Parts.Exceptions.size() != 0) {
992 Result <<
"<Exceptions>";
993 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
994 visit(Parts.Exceptions[i]);
995 Result <<
"</Exceptions>";
998 if (Parts.Returns.size() != 0) {
999 Result <<
"<ResultDiscussion>";
1000 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
1001 visit(Parts.Returns[i]);
1002 Result <<
"</ResultDiscussion>";
1007 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
1008 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
1010 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
1011 if (DA->getMessage().empty())
1012 Result <<
"<Deprecated/>";
1014 Result <<
"<Deprecated>";
1015 appendToResultWithXMLEscaping(DA->getMessage());
1016 Result <<
"</Deprecated>";
1019 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1020 if (UA->getMessage().empty())
1021 Result <<
"<Unavailable/>";
1023 Result <<
"<Unavailable>";
1024 appendToResultWithXMLEscaping(UA->getMessage());
1025 Result <<
"</Unavailable>";
1032 Result <<
"<Availability";
1033 StringRef Distribution;
1034 if (AA->getPlatform()) {
1035 Distribution = AvailabilityAttr::getPrettyPlatformName(
1036 AA->getPlatform()->getName());
1037 if (Distribution.empty())
1038 Distribution = AA->getPlatform()->getName();
1040 Result <<
" distribution=\"" << Distribution <<
"\">";
1041 VersionTuple IntroducedInVersion = AA->getIntroduced();
1042 if (!IntroducedInVersion.empty()) {
1043 Result <<
"<IntroducedInVersion>"
1044 << IntroducedInVersion.getAsString()
1045 <<
"</IntroducedInVersion>";
1047 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1048 if (!DeprecatedInVersion.empty()) {
1049 Result <<
"<DeprecatedInVersion>"
1050 << DeprecatedInVersion.getAsString()
1051 <<
"</DeprecatedInVersion>";
1053 VersionTuple RemovedAfterVersion = AA->getObsoleted();
1054 if (!RemovedAfterVersion.empty()) {
1055 Result <<
"<RemovedAfterVersion>"
1056 << RemovedAfterVersion.getAsString()
1057 <<
"</RemovedAfterVersion>";
1059 StringRef DeprecationSummary = AA->getMessage();
1060 if (!DeprecationSummary.empty()) {
1061 Result <<
"<DeprecationSummary>";
1062 appendToResultWithXMLEscaping(DeprecationSummary);
1063 Result <<
"</DeprecationSummary>";
1065 if (AA->getUnavailable())
1066 Result <<
"<Unavailable/>";
1070 Result <<
"<Environment>" << Environment->
getName() <<
"</Environment>";
1072 Result <<
"</Availability>";
1077 bool StartTagEmitted =
false;
1078 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1079 const Comment *
C = Parts.MiscBlocks[i];
1080 if (FirstParagraphIsBrief &&
C == Parts.FirstParagraph)
1082 if (!StartTagEmitted) {
1083 Result <<
"<Discussion>";
1084 StartTagEmitted =
true;
1088 if (StartTagEmitted)
1089 Result <<
"</Discussion>";
1092 Result << RootEndTag;
1095void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1096 for (StringRef::iterator I = S.begin(),
E = S.end(); I !=
E; ++I) {
1121void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1125 Result <<
"<![CDATA[";
1126 while (!S.empty()) {
1127 size_t Pos = S.find(
"]]>");
1129 Result <<
"]]]]><![CDATA[>";
1130 S = S.drop_front(3);
1133 if (Pos == StringRef::npos)
1136 Result << S.substr(0, Pos);
1138 S = S.drop_front(Pos);
1149 CommentASTToHTMLConverter Converter(FC, HTML,
1151 Converter.visit(FC);
1157 CommentASTToHTMLConverter Converter(
nullptr,
Text,
1159 Converter.visit(HTC);
1167 Converter.visit(FC);
Defines the clang::ASTContext interface.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Defines the SourceManager interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
comments::CommandTraits & getCommentCommandTraits() const
const LangOptions & getLangOpts() const
Attr - This represents one attribute.
ASTContext & getASTContext() const LLVM_READONLY
SourceLocation getLocation() const
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
The name of a declaration.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
This represents a decl that may have a name.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
bool generateUSRForDecl(const Decl *D, SmallVectorImpl< char > &Buf)
Generate a USR for a Decl, including the USR prefix.
The JSON file list parser is used to communicate input to InstallAPI.
std::pair< FileID, unsigned > FileIDAndOffset
@ Result
The result type of a method or function.
Describes how types, statements, expressions, and declarations should be printed.