19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/ADT/TinyPtrVector.h"
21 #include "llvm/Support/raw_ostream.h"
23 using namespace clang;
31 class ParamCommandCommentCompareIndex {
50 return LHSIndex < RHSIndex;
58 class TParamCommandCommentComparePosition {
83 struct FullCommentParts {
94 llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
98 FullCommentParts::FullCommentParts(
const FullComment *C,
100 Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
106 switch (Child->getCommentKind()) {
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())
218 class CommentASTToHTMLConverter :
225 FC(FC), Result(Str), Traits(Traits)
251 void appendToResultWithHTMLEscaping(StringRef S);
256 llvm::raw_svector_ostream Result;
262 void CommentASTToHTMLConverter::visitTextComment(
const TextComment *
C) {
263 appendToResultWithHTMLEscaping(
C->getText());
266 void 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>";
310 void CommentASTToHTMLConverter::visitHTMLStartTagComment(
312 printHTMLStartTagComment(
C, Result);
315 void CommentASTToHTMLConverter::visitHTMLEndTagComment(
317 Result <<
"</" <<
C->getTagName() <<
">";
320 void CommentASTToHTMLConverter::visitParagraphComment(
322 if (
C->isWhitespace())
333 void 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());
353 void 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());
385 void 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());
416 void 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)
431 void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
433 llvm_unreachable(
"should not see this AST node");
436 void CommentASTToHTMLConverter::visitVerbatimLineComment(
439 appendToResultWithHTMLEscaping(
C->getText());
443 void 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]);
488 void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
499 void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
500 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
529 class CommentASTToXMLConverter :
537 FC(FC), Result(Str), Traits(Traits),
SM(
SM) { }
561 void appendToResultWithXMLEscaping(StringRef S);
562 void appendToResultWithCDATAEscaping(StringRef S);
564 void formatTextOfDeclaration(
const DeclInfo *DI,
571 llvm::raw_svector_ostream Result;
577 void getSourceTextOfDeclaration(
const DeclInfo *ThisDecl,
581 llvm::raw_svector_ostream
OS(Str);
583 PPolicy.PolishForDeclaration =
true;
584 PPolicy.TerseOutput =
true;
585 PPolicy.ConstantsAsWritten =
true;
590 void CommentASTToXMLConverter::formatTextOfDeclaration(
600 Style.FixNamespaceComments =
false;
604 if (
static_cast<bool>(FormattedStringDecl)) {
611 void CommentASTToXMLConverter::visitTextComment(
const TextComment *
C) {
612 appendToResultWithXMLEscaping(
C->getText());
615 void 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>";
658 void 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>";
685 appendParagraphCommentWithKind(
C, StringRef());
688 void CommentASTToXMLConverter::appendParagraphCommentWithKind(
690 StringRef ParagraphKind) {
691 if (
C->isWhitespace())
694 if (ParagraphKind.empty())
697 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
706 void CommentASTToXMLConverter::visitBlockCommandComment(
708 StringRef ParagraphKind;
710 switch (
C->getCommandID()) {
711 case CommandTraits::KCI_attention:
712 case CommandTraits::KCI_author:
713 case CommandTraits::KCI_authors:
714 case CommandTraits::KCI_bug:
715 case CommandTraits::KCI_copyright:
716 case CommandTraits::KCI_date:
717 case CommandTraits::KCI_invariant:
718 case CommandTraits::KCI_note:
719 case CommandTraits::KCI_post:
720 case CommandTraits::KCI_pre:
721 case CommandTraits::KCI_remark:
722 case CommandTraits::KCI_remarks:
723 case CommandTraits::KCI_sa:
724 case CommandTraits::KCI_see:
725 case CommandTraits::KCI_since:
726 case CommandTraits::KCI_todo:
727 case CommandTraits::KCI_version:
728 case CommandTraits::KCI_warning:
729 ParagraphKind =
C->getCommandName(Traits);
735 appendParagraphCommentWithKind(
C->getParagraph(), ParagraphKind);
738 void CommentASTToXMLConverter::visitParamCommandComment(
740 Result <<
"<Parameter><Name>";
741 appendToResultWithXMLEscaping(
C->isParamIndexValid()
742 ?
C->getParamName(FC)
743 :
C->getParamNameAsWritten());
746 if (
C->isParamIndexValid()) {
747 if (
C->isVarArgParam())
748 Result <<
"<IsVarArg />";
750 Result <<
"<Index>" <<
C->getParamIndex() <<
"</Index>";
753 Result <<
"<Direction isExplicit=\"" <<
C->isDirectionExplicit() <<
"\">";
754 switch (
C->getDirection()) {
755 case ParamCommandPassDirection::In:
758 case ParamCommandPassDirection::Out:
761 case ParamCommandPassDirection::InOut:
765 Result <<
"</Direction><Discussion>";
766 visit(
C->getParagraph());
767 Result <<
"</Discussion></Parameter>";
770 void CommentASTToXMLConverter::visitTParamCommandComment(
772 Result <<
"<Parameter><Name>";
773 appendToResultWithXMLEscaping(
C->isPositionValid() ?
C->getParamName(FC)
774 :
C->getParamNameAsWritten());
777 if (
C->isPositionValid() &&
C->getDepth() == 1) {
778 Result <<
"<Index>" <<
C->getIndex(0) <<
"</Index>";
781 Result <<
"<Discussion>";
782 visit(
C->getParagraph());
783 Result <<
"</Discussion></Parameter>";
786 void CommentASTToXMLConverter::visitVerbatimBlockComment(
788 unsigned NumLines =
C->getNumLines();
792 switch (
C->getCommandID()) {
793 case CommandTraits::KCI_code:
794 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
797 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
800 for (
unsigned i = 0; i != NumLines; ++i) {
801 appendToResultWithXMLEscaping(
C->getText(i));
802 if (i + 1 != NumLines)
805 Result <<
"</Verbatim>";
808 void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
810 llvm_unreachable(
"should not see this AST node");
813 void CommentASTToXMLConverter::visitVerbatimLineComment(
815 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
816 appendToResultWithXMLEscaping(
C->getText());
817 Result <<
"</Verbatim>";
820 void CommentASTToXMLConverter::visitFullComment(
const FullComment *
C) {
821 FullCommentParts Parts(
C, Traits);
824 StringRef RootEndTag;
827 case DeclInfo::OtherKind:
828 RootEndTag =
"</Other>";
831 case DeclInfo::FunctionKind:
832 RootEndTag =
"</Function>";
833 Result <<
"<Function";
835 case DeclInfo::NotTemplate:
837 case DeclInfo::Template:
838 Result <<
" templateKind=\"template\"";
840 case DeclInfo::TemplateSpecialization:
841 Result <<
" templateKind=\"specialization\"";
843 case DeclInfo::TemplatePartialSpecialization:
844 llvm_unreachable(
"partial specializations of functions "
845 "are not allowed in C++");
848 Result <<
" isInstanceMethod=\"1\"";
850 Result <<
" isClassMethod=\"1\"";
852 case DeclInfo::ClassKind:
853 RootEndTag =
"</Class>";
856 case DeclInfo::NotTemplate:
858 case DeclInfo::Template:
859 Result <<
" templateKind=\"template\"";
861 case DeclInfo::TemplateSpecialization:
862 Result <<
" templateKind=\"specialization\"";
864 case DeclInfo::TemplatePartialSpecialization:
865 Result <<
" templateKind=\"partialSpecialization\"";
869 case DeclInfo::VariableKind:
870 RootEndTag =
"</Variable>";
871 Result <<
"<Variable";
873 case DeclInfo::NamespaceKind:
874 RootEndTag =
"</Namespace>";
875 Result <<
"<Namespace";
877 case DeclInfo::TypedefKind:
878 RootEndTag =
"</Typedef>";
879 Result <<
"<Typedef";
881 case DeclInfo::EnumKind:
882 RootEndTag =
"</Enum>";
890 std::pair<FileID, unsigned> LocInfo =
SM.getDecomposedLoc(
Loc);
891 FileID FID = LocInfo.first;
892 unsigned FileOffset = LocInfo.second;
896 Result <<
" file=\"";
897 appendToResultWithXMLEscaping(FE->getName());
900 Result <<
" line=\"" <<
SM.getLineNumber(FID, FileOffset)
901 <<
"\" column=\"" <<
SM.getColumnNumber(FID, FileOffset)
909 bool FoundName =
false;
913 std::string Name = DeclName.getAsString();
914 appendToResultWithXMLEscaping(Name);
920 Result <<
"<Name><anonymous></Name>";
928 appendToResultWithXMLEscaping(USR);
934 RootEndTag =
"</Other>";
935 Result <<
"<Other><Name>unknown</Name>";
938 if (Parts.Headerfile) {
939 Result <<
"<Headerfile>";
940 visit(Parts.Headerfile);
941 Result <<
"</Headerfile>";
946 Result <<
"<Declaration>";
948 getSourceTextOfDeclaration(DI, Declaration);
949 formatTextOfDeclaration(DI, Declaration);
950 appendToResultWithXMLEscaping(Declaration);
951 Result <<
"</Declaration>";
954 bool FirstParagraphIsBrief =
false;
956 Result <<
"<Abstract>";
958 Result <<
"</Abstract>";
959 }
else if (Parts.FirstParagraph) {
960 Result <<
"<Abstract>";
961 visit(Parts.FirstParagraph);
962 Result <<
"</Abstract>";
963 FirstParagraphIsBrief =
true;
966 if (Parts.TParams.size() != 0) {
967 Result <<
"<TemplateParameters>";
968 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
969 visit(Parts.TParams[i]);
970 Result <<
"</TemplateParameters>";
973 if (Parts.Params.size() != 0) {
974 Result <<
"<Parameters>";
975 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
976 visit(Parts.Params[i]);
977 Result <<
"</Parameters>";
980 if (Parts.Exceptions.size() != 0) {
981 Result <<
"<Exceptions>";
982 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
983 visit(Parts.Exceptions[i]);
984 Result <<
"</Exceptions>";
987 if (Parts.Returns.size() != 0) {
988 Result <<
"<ResultDiscussion>";
989 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
990 visit(Parts.Returns[i]);
991 Result <<
"</ResultDiscussion>";
996 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
997 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
999 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
1000 if (DA->getMessage().empty())
1001 Result <<
"<Deprecated/>";
1003 Result <<
"<Deprecated>";
1004 appendToResultWithXMLEscaping(DA->getMessage());
1005 Result <<
"</Deprecated>";
1008 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1009 if (UA->getMessage().empty())
1010 Result <<
"<Unavailable/>";
1012 Result <<
"<Unavailable>";
1013 appendToResultWithXMLEscaping(UA->getMessage());
1014 Result <<
"</Unavailable>";
1021 Result <<
"<Availability";
1022 StringRef Distribution;
1023 if (AA->getPlatform()) {
1024 Distribution = AvailabilityAttr::getPrettyPlatformName(
1025 AA->getPlatform()->getName());
1026 if (Distribution.empty())
1027 Distribution = AA->getPlatform()->getName();
1029 Result <<
" distribution=\"" << Distribution <<
"\">";
1030 VersionTuple IntroducedInVersion = AA->getIntroduced();
1031 if (!IntroducedInVersion.empty()) {
1032 Result <<
"<IntroducedInVersion>"
1033 << IntroducedInVersion.getAsString()
1034 <<
"</IntroducedInVersion>";
1036 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1037 if (!DeprecatedInVersion.empty()) {
1038 Result <<
"<DeprecatedInVersion>"
1039 << DeprecatedInVersion.getAsString()
1040 <<
"</DeprecatedInVersion>";
1042 VersionTuple RemovedAfterVersion = AA->getObsoleted();
1043 if (!RemovedAfterVersion.empty()) {
1044 Result <<
"<RemovedAfterVersion>"
1045 << RemovedAfterVersion.getAsString()
1046 <<
"</RemovedAfterVersion>";
1048 StringRef DeprecationSummary = AA->getMessage();
1049 if (!DeprecationSummary.empty()) {
1050 Result <<
"<DeprecationSummary>";
1051 appendToResultWithXMLEscaping(DeprecationSummary);
1052 Result <<
"</DeprecationSummary>";
1054 if (AA->getUnavailable())
1055 Result <<
"<Unavailable/>";
1059 Result <<
"<Environment>" << Environment->
getName() <<
"</Environment>";
1061 Result <<
"</Availability>";
1066 bool StartTagEmitted =
false;
1067 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1068 const Comment *
C = Parts.MiscBlocks[i];
1069 if (FirstParagraphIsBrief &&
C == Parts.FirstParagraph)
1071 if (!StartTagEmitted) {
1072 Result <<
"<Discussion>";
1073 StartTagEmitted =
true;
1077 if (StartTagEmitted)
1078 Result <<
"</Discussion>";
1081 Result << RootEndTag;
1084 void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1085 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
1110 void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1114 Result <<
"<![CDATA[";
1115 while (!S.empty()) {
1116 size_t Pos = S.find(
"]]>");
1118 Result <<
"]]]]><![CDATA[>";
1119 S = S.drop_front(3);
1122 if (Pos == StringRef::npos)
1125 Result << S.substr(0, Pos);
1127 S = S.drop_front(Pos);
1132 CommentToXMLConverter::CommentToXMLConverter() {}
1138 CommentASTToHTMLConverter Converter(FC, HTML,
1140 Converter.visit(FC);
1146 CommentASTToHTMLConverter Converter(
nullptr,
Text,
1148 Converter.visit(HTC);
1156 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()
const LangOptions & getLangOpts() const
comments::CommandTraits & getCommentCommandTraits() 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.
constexpr XRayInstrMask None
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.
Describes how types, statements, expressions, and declarations should be printed.