19#include "llvm/ADT/StringExtras.h"
20#include "llvm/ADT/TinyPtrVector.h"
21#include "llvm/Support/raw_ostream.h"
31class ParamCommandCommentCompareIndex {
50 return LHSIndex < RHSIndex;
58class TParamCommandCommentComparePosition {
83struct FullCommentParts {
94 llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
100 Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
106 switch (Child->getCommentKind()) {
107 case CommentKind::None:
110 case CommentKind::ParagraphComment: {
117 MiscBlocks.push_back(PC);
121 case CommentKind::BlockCommandComment: {
133 Returns.push_back(BCC);
137 Exceptions.push_back(BCC);
140 MiscBlocks.push_back(BCC);
144 case CommentKind::ParamCommandComment: {
152 Params.push_back(PCC);
156 case CommentKind::TParamCommandComment: {
164 TParams.push_back(TPCC);
168 case CommentKind::VerbatimBlockComment:
169 MiscBlocks.push_back(cast<BlockCommandComment>(Child));
172 case CommentKind::VerbatimLineComment: {
176 MiscBlocks.push_back(VLC);
180 case CommentKind::TextComment:
181 case CommentKind::InlineCommandComment:
182 case CommentKind::HTMLStartTagComment:
183 case CommentKind::HTMLEndTagComment:
184 case CommentKind::VerbatimBlockLineComment:
185 case CommentKind::FullComment:
186 llvm_unreachable(
"AST node of this kind can't be a child of "
194 llvm::stable_sort(Params, ParamCommandCommentCompareIndex());
195 llvm::stable_sort(TParams, TParamCommandCommentComparePosition());
199 llvm::raw_svector_ostream &Result) {
200 Result <<
"<" <<
C->getTagName();
202 if (
C->getNumAttrs() != 0) {
203 for (
unsigned i = 0, e =
C->getNumAttrs(); i != e; i++) {
207 if (!
Attr.Value.empty())
208 Result <<
"=\"" <<
Attr.Value <<
"\"";
212 if (!
C->isSelfClosing())
218class CommentASTToHTMLConverter :
225 FC(FC), Result(Str), Traits(Traits)
251 void appendToResultWithHTMLEscaping(StringRef S);
256 llvm::raw_svector_ostream
Result;
262void CommentASTToHTMLConverter::visitTextComment(
const TextComment *
C) {
263 appendToResultWithHTMLEscaping(
C->getText());
266void CommentASTToHTMLConverter::visitInlineCommandComment(
269 if (
C->getNumArgs() == 0)
273 StringRef Arg0 =
C->getArgText(0);
277 switch (
C->getRenderKind()) {
278 case InlineCommandRenderKind::Normal:
279 for (
unsigned i = 0, e =
C->getNumArgs(); i != e; ++i) {
280 appendToResultWithHTMLEscaping(
C->getArgText(i));
285 case InlineCommandRenderKind::Bold:
286 assert(
C->getNumArgs() == 1);
288 appendToResultWithHTMLEscaping(Arg0);
291 case InlineCommandRenderKind::Monospaced:
292 assert(
C->getNumArgs() == 1);
294 appendToResultWithHTMLEscaping(Arg0);
297 case InlineCommandRenderKind::Emphasized:
298 assert(
C->getNumArgs() == 1);
300 appendToResultWithHTMLEscaping(Arg0);
303 case InlineCommandRenderKind::Anchor:
304 assert(
C->getNumArgs() == 1);
305 Result <<
"<span id=\"" << Arg0 <<
"\"></span>";
310void CommentASTToHTMLConverter::visitHTMLStartTagComment(
312 printHTMLStartTagComment(
C, Result);
315void CommentASTToHTMLConverter::visitHTMLEndTagComment(
317 Result <<
"</" <<
C->getTagName() <<
">";
320void CommentASTToHTMLConverter::visitParagraphComment(
322 if (
C->isWhitespace())
333void CommentASTToHTMLConverter::visitBlockCommandComment(
337 Result <<
"<p class=\"para-brief\">";
338 visitNonStandaloneParagraphComment(
C->getParagraph());
343 Result <<
"<p class=\"para-returns\">"
344 "<span class=\"word-returns\">Returns</span> ";
345 visitNonStandaloneParagraphComment(
C->getParagraph());
350 visit(
C->getParagraph());
353void CommentASTToHTMLConverter::visitParamCommandComment(
355 if (
C->isParamIndexValid()) {
356 if (
C->isVarArgParam()) {
357 Result <<
"<dt class=\"param-name-index-vararg\">";
358 appendToResultWithHTMLEscaping(
C->getParamNameAsWritten());
360 Result <<
"<dt class=\"param-name-index-"
361 <<
C->getParamIndex()
363 appendToResultWithHTMLEscaping(
C->getParamName(FC));
366 Result <<
"<dt class=\"param-name-index-invalid\">";
367 appendToResultWithHTMLEscaping(
C->getParamNameAsWritten());
371 if (
C->isParamIndexValid()) {
372 if (
C->isVarArgParam())
373 Result <<
"<dd class=\"param-descr-index-vararg\">";
375 Result <<
"<dd class=\"param-descr-index-"
376 <<
C->getParamIndex()
379 Result <<
"<dd class=\"param-descr-index-invalid\">";
381 visitNonStandaloneParagraphComment(
C->getParagraph());
385void CommentASTToHTMLConverter::visitTParamCommandComment(
387 if (
C->isPositionValid()) {
388 if (
C->getDepth() == 1)
389 Result <<
"<dt class=\"tparam-name-index-"
393 Result <<
"<dt class=\"tparam-name-index-other\">";
394 appendToResultWithHTMLEscaping(
C->getParamName(FC));
396 Result <<
"<dt class=\"tparam-name-index-invalid\">";
397 appendToResultWithHTMLEscaping(
C->getParamNameAsWritten());
402 if (
C->isPositionValid()) {
403 if (
C->getDepth() == 1)
404 Result <<
"<dd class=\"tparam-descr-index-"
408 Result <<
"<dd class=\"tparam-descr-index-other\">";
410 Result <<
"<dd class=\"tparam-descr-index-invalid\">";
412 visitNonStandaloneParagraphComment(
C->getParagraph());
416void CommentASTToHTMLConverter::visitVerbatimBlockComment(
418 unsigned NumLines =
C->getNumLines();
423 for (
unsigned i = 0; i != NumLines; ++i) {
424 appendToResultWithHTMLEscaping(
C->getText(i));
425 if (i + 1 != NumLines)
431void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
433 llvm_unreachable(
"should not see this AST node");
436void CommentASTToHTMLConverter::visitVerbatimLineComment(
439 appendToResultWithHTMLEscaping(
C->getText());
443void CommentASTToHTMLConverter::visitFullComment(
const FullComment *
C) {
444 FullCommentParts Parts(
C, Traits);
446 bool FirstParagraphIsBrief =
false;
447 if (Parts.Headerfile)
448 visit(Parts.Headerfile);
451 else if (Parts.FirstParagraph) {
452 Result <<
"<p class=\"para-brief\">";
453 visitNonStandaloneParagraphComment(Parts.FirstParagraph);
455 FirstParagraphIsBrief =
true;
458 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
459 const Comment *
C = Parts.MiscBlocks[i];
460 if (FirstParagraphIsBrief &&
C == Parts.FirstParagraph)
465 if (Parts.TParams.size() != 0) {
467 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
468 visit(Parts.TParams[i]);
472 if (Parts.Params.size() != 0) {
474 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
475 visit(Parts.Params[i]);
479 if (Parts.Returns.size() != 0) {
480 Result <<
"<div class=\"result-discussion\">";
481 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
482 visit(Parts.Returns[i]);
488void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
499void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
500 for (StringRef::iterator I = S.begin(),
E = S.end(); I !=
E; ++I) {
529class CommentASTToXMLConverter :
537 FC(FC), Result(Str), Traits(Traits),
SM(
SM) { }
549 StringRef ParagraphKind,
550 StringRef PrependBodyText);
562 void appendToResultWithXMLEscaping(StringRef S);
563 void appendToResultWithCDATAEscaping(StringRef S);
565 void formatTextOfDeclaration(
const DeclInfo *DI,
572 llvm::raw_svector_ostream
Result;
578void getSourceTextOfDeclaration(
const DeclInfo *ThisDecl,
582 llvm::raw_svector_ostream OS(Str);
584 PPolicy.PolishForDeclaration =
true;
585 PPolicy.TerseOutput =
true;
586 PPolicy.ConstantsAsWritten =
true;
591void CommentASTToXMLConverter::formatTextOfDeclaration(
601 Style.FixNamespaceComments =
false;
605 if (
static_cast<bool>(FormattedStringDecl)) {
612void CommentASTToXMLConverter::visitTextComment(
const TextComment *
C) {
613 appendToResultWithXMLEscaping(
C->getText());
616void CommentASTToXMLConverter::visitInlineCommandComment(
619 if (
C->getNumArgs() == 0)
623 StringRef Arg0 =
C->getArgText(0);
627 switch (
C->getRenderKind()) {
628 case InlineCommandRenderKind::Normal:
629 for (
unsigned i = 0, e =
C->getNumArgs(); i != e; ++i) {
630 appendToResultWithXMLEscaping(
C->getArgText(i));
634 case InlineCommandRenderKind::Bold:
635 assert(
C->getNumArgs() == 1);
637 appendToResultWithXMLEscaping(Arg0);
640 case InlineCommandRenderKind::Monospaced:
641 assert(
C->getNumArgs() == 1);
642 Result <<
"<monospaced>";
643 appendToResultWithXMLEscaping(Arg0);
644 Result <<
"</monospaced>";
646 case InlineCommandRenderKind::Emphasized:
647 assert(
C->getNumArgs() == 1);
648 Result <<
"<emphasized>";
649 appendToResultWithXMLEscaping(Arg0);
650 Result <<
"</emphasized>";
652 case InlineCommandRenderKind::Anchor:
653 assert(
C->getNumArgs() == 1);
654 Result <<
"<anchor id=\"" << Arg0 <<
"\"></anchor>";
659void CommentASTToXMLConverter::visitHTMLStartTagComment(
661 Result <<
"<rawHTML";
662 if (
C->isMalformed())
663 Result <<
" isMalformed=\"1\"";
668 llvm::raw_svector_ostream TagOS(Tag);
669 printHTMLStartTagComment(
C, TagOS);
671 appendToResultWithCDATAEscaping(Tag);
673 Result <<
"</rawHTML>";
678 Result <<
"<rawHTML";
679 if (
C->isMalformed())
680 Result <<
" isMalformed=\"1\"";
681 Result <<
"></" <<
C->getTagName() <<
"></rawHTML>";
684void CommentASTToXMLConverter::visitParagraphComment(
686 appendParagraphCommentWithKind(
C, StringRef(), StringRef());
689void CommentASTToXMLConverter::appendParagraphCommentWithKind(
691 StringRef PrependBodyText) {
692 if (
C->isWhitespace() && PrependBodyText.empty())
695 if (ParagraphKind.empty())
698 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
700 if (!PrependBodyText.empty())
701 Result << PrependBodyText <<
" ";
710void CommentASTToXMLConverter::visitBlockCommandComment(
712 StringRef ParagraphKind;
713 StringRef ExceptionType;
715 const unsigned CommandID =
C->getCommandID();
718 ExceptionType =
C->getArgText(0);
722 case CommandTraits::KCI_attention:
723 case CommandTraits::KCI_author:
724 case CommandTraits::KCI_authors:
725 case CommandTraits::KCI_bug:
726 case CommandTraits::KCI_copyright:
727 case CommandTraits::KCI_date:
728 case CommandTraits::KCI_invariant:
729 case CommandTraits::KCI_note:
730 case CommandTraits::KCI_post:
731 case CommandTraits::KCI_pre:
732 case CommandTraits::KCI_remark:
733 case CommandTraits::KCI_remarks:
734 case CommandTraits::KCI_sa:
735 case CommandTraits::KCI_see:
736 case CommandTraits::KCI_since:
737 case CommandTraits::KCI_todo:
738 case CommandTraits::KCI_version:
739 case CommandTraits::KCI_warning:
740 ParagraphKind =
C->getCommandName(Traits);
746 appendParagraphCommentWithKind(
C->getParagraph(), ParagraphKind,
750void CommentASTToXMLConverter::visitParamCommandComment(
752 Result <<
"<Parameter><Name>";
753 appendToResultWithXMLEscaping(
C->isParamIndexValid()
754 ?
C->getParamName(FC)
755 :
C->getParamNameAsWritten());
758 if (
C->isParamIndexValid()) {
759 if (
C->isVarArgParam())
760 Result <<
"<IsVarArg />";
762 Result <<
"<Index>" <<
C->getParamIndex() <<
"</Index>";
765 Result <<
"<Direction isExplicit=\"" <<
C->isDirectionExplicit() <<
"\">";
766 switch (
C->getDirection()) {
767 case ParamCommandPassDirection::In:
770 case ParamCommandPassDirection::Out:
773 case ParamCommandPassDirection::InOut:
777 Result <<
"</Direction><Discussion>";
778 visit(
C->getParagraph());
779 Result <<
"</Discussion></Parameter>";
782void CommentASTToXMLConverter::visitTParamCommandComment(
784 Result <<
"<Parameter><Name>";
785 appendToResultWithXMLEscaping(
C->isPositionValid() ?
C->getParamName(FC)
786 :
C->getParamNameAsWritten());
789 if (
C->isPositionValid() &&
C->getDepth() == 1) {
790 Result <<
"<Index>" <<
C->getIndex(0) <<
"</Index>";
793 Result <<
"<Discussion>";
794 visit(
C->getParagraph());
795 Result <<
"</Discussion></Parameter>";
798void CommentASTToXMLConverter::visitVerbatimBlockComment(
800 unsigned NumLines =
C->getNumLines();
804 switch (
C->getCommandID()) {
805 case CommandTraits::KCI_code:
806 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
809 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
812 for (
unsigned i = 0; i != NumLines; ++i) {
813 appendToResultWithXMLEscaping(
C->getText(i));
814 if (i + 1 != NumLines)
817 Result <<
"</Verbatim>";
820void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
822 llvm_unreachable(
"should not see this AST node");
825void CommentASTToXMLConverter::visitVerbatimLineComment(
827 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
828 appendToResultWithXMLEscaping(
C->getText());
829 Result <<
"</Verbatim>";
832void CommentASTToXMLConverter::visitFullComment(
const FullComment *
C) {
833 FullCommentParts Parts(
C, Traits);
836 StringRef RootEndTag;
840 RootEndTag =
"</Other>";
844 RootEndTag =
"</Function>";
845 Result <<
"<Function";
850 Result <<
" templateKind=\"template\"";
853 Result <<
" templateKind=\"specialization\"";
856 llvm_unreachable(
"partial specializations of functions "
857 "are not allowed in C++");
860 Result <<
" isInstanceMethod=\"1\"";
862 Result <<
" isClassMethod=\"1\"";
865 RootEndTag =
"</Class>";
871 Result <<
" templateKind=\"template\"";
874 Result <<
" templateKind=\"specialization\"";
877 Result <<
" templateKind=\"partialSpecialization\"";
882 RootEndTag =
"</Variable>";
883 Result <<
"<Variable";
886 RootEndTag =
"</Namespace>";
887 Result <<
"<Namespace";
890 RootEndTag =
"</Typedef>";
891 Result <<
"<Typedef";
894 RootEndTag =
"</Enum>";
902 std::pair<FileID, unsigned> LocInfo =
SM.getDecomposedLoc(
Loc);
903 FileID FID = LocInfo.first;
904 unsigned FileOffset = LocInfo.second;
908 Result <<
" file=\"";
909 appendToResultWithXMLEscaping(FE->getName());
912 Result <<
" line=\"" <<
SM.getLineNumber(FID, FileOffset)
913 <<
"\" column=\"" <<
SM.getColumnNumber(FID, FileOffset)
921 bool FoundName =
false;
925 std::string Name = DeclName.getAsString();
926 appendToResultWithXMLEscaping(Name);
932 Result <<
"<Name><anonymous></Name>";
940 appendToResultWithXMLEscaping(USR);
946 RootEndTag =
"</Other>";
947 Result <<
"<Other><Name>unknown</Name>";
950 if (Parts.Headerfile) {
951 Result <<
"<Headerfile>";
952 visit(Parts.Headerfile);
953 Result <<
"</Headerfile>";
958 Result <<
"<Declaration>";
963 Result <<
"</Declaration>";
966 bool FirstParagraphIsBrief =
false;
968 Result <<
"<Abstract>";
970 Result <<
"</Abstract>";
971 }
else if (Parts.FirstParagraph) {
972 Result <<
"<Abstract>";
973 visit(Parts.FirstParagraph);
974 Result <<
"</Abstract>";
975 FirstParagraphIsBrief =
true;
978 if (Parts.TParams.size() != 0) {
979 Result <<
"<TemplateParameters>";
980 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
981 visit(Parts.TParams[i]);
982 Result <<
"</TemplateParameters>";
985 if (Parts.Params.size() != 0) {
986 Result <<
"<Parameters>";
987 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
988 visit(Parts.Params[i]);
989 Result <<
"</Parameters>";
992 if (Parts.Exceptions.size() != 0) {
993 Result <<
"<Exceptions>";
994 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
995 visit(Parts.Exceptions[i]);
996 Result <<
"</Exceptions>";
999 if (Parts.Returns.size() != 0) {
1000 Result <<
"<ResultDiscussion>";
1001 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
1002 visit(Parts.Returns[i]);
1003 Result <<
"</ResultDiscussion>";
1008 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
1009 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
1011 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
1012 if (DA->getMessage().empty())
1013 Result <<
"<Deprecated/>";
1015 Result <<
"<Deprecated>";
1016 appendToResultWithXMLEscaping(DA->getMessage());
1017 Result <<
"</Deprecated>";
1020 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1021 if (UA->getMessage().empty())
1022 Result <<
"<Unavailable/>";
1024 Result <<
"<Unavailable>";
1025 appendToResultWithXMLEscaping(UA->getMessage());
1026 Result <<
"</Unavailable>";
1033 Result <<
"<Availability";
1034 StringRef Distribution;
1035 if (AA->getPlatform()) {
1036 Distribution = AvailabilityAttr::getPrettyPlatformName(
1037 AA->getPlatform()->getName());
1038 if (Distribution.empty())
1039 Distribution = AA->getPlatform()->getName();
1041 Result <<
" distribution=\"" << Distribution <<
"\">";
1042 VersionTuple IntroducedInVersion = AA->getIntroduced();
1043 if (!IntroducedInVersion.empty()) {
1044 Result <<
"<IntroducedInVersion>"
1045 << IntroducedInVersion.getAsString()
1046 <<
"</IntroducedInVersion>";
1048 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1049 if (!DeprecatedInVersion.empty()) {
1050 Result <<
"<DeprecatedInVersion>"
1051 << DeprecatedInVersion.getAsString()
1052 <<
"</DeprecatedInVersion>";
1054 VersionTuple RemovedAfterVersion = AA->getObsoleted();
1055 if (!RemovedAfterVersion.empty()) {
1056 Result <<
"<RemovedAfterVersion>"
1057 << RemovedAfterVersion.getAsString()
1058 <<
"</RemovedAfterVersion>";
1060 StringRef DeprecationSummary = AA->getMessage();
1061 if (!DeprecationSummary.empty()) {
1062 Result <<
"<DeprecationSummary>";
1063 appendToResultWithXMLEscaping(DeprecationSummary);
1064 Result <<
"</DeprecationSummary>";
1066 if (AA->getUnavailable())
1067 Result <<
"<Unavailable/>";
1071 Result <<
"<Environment>" << Environment->
getName() <<
"</Environment>";
1073 Result <<
"</Availability>";
1078 bool StartTagEmitted =
false;
1079 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1080 const Comment *
C = Parts.MiscBlocks[i];
1081 if (FirstParagraphIsBrief &&
C == Parts.FirstParagraph)
1083 if (!StartTagEmitted) {
1084 Result <<
"<Discussion>";
1085 StartTagEmitted =
true;
1089 if (StartTagEmitted)
1090 Result <<
"</Discussion>";
1093 Result << RootEndTag;
1096void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1097 for (StringRef::iterator I = S.begin(),
E = S.end(); I !=
E; ++I) {
1122void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1126 Result <<
"<![CDATA[";
1127 while (!S.empty()) {
1128 size_t Pos = S.find(
"]]>");
1130 Result <<
"]]]]><![CDATA[>";
1131 S = S.drop_front(3);
1134 if (Pos == StringRef::npos)
1137 Result << S.substr(0, Pos);
1139 S = S.drop_front(Pos);
1150 CommentASTToHTMLConverter Converter(FC, HTML,
1152 Converter.visit(FC);
1158 CommentASTToHTMLConverter Converter(
nullptr,
Text,
1160 Converter.visit(HTC);
1168 Converter.visit(FC);
Defines the clang::ASTContext interface.
Defines the clang::FileManager interface and associated types.
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.
@ Result
The result type of a method or function.
Describes how types, statements, expressions, and declarations should be printed.