17 #include "llvm/ADT/StringExtras.h" 18 #include "llvm/ADT/TinyPtrVector.h" 19 #include "llvm/Support/raw_ostream.h" 21 using namespace clang;
29 class ParamCommandCommentCompareIndex {
48 return LHSIndex < RHSIndex;
56 class TParamCommandCommentComparePosition {
81 struct FullCommentParts {
92 llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
96 FullCommentParts::FullCommentParts(
const FullComment *C,
98 Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
105 case Comment::NoCommentKind:
108 case Comment::ParagraphCommentKind: {
115 MiscBlocks.push_back(PC);
119 case Comment::BlockCommandCommentKind: {
122 if (!Brief && Info->IsBriefCommand) {
126 if (!Headerfile && Info->IsHeaderfileCommand) {
130 if (Info->IsReturnsCommand) {
131 Returns.push_back(BCC);
134 if (Info->IsThrowsCommand) {
135 Exceptions.push_back(BCC);
138 MiscBlocks.push_back(BCC);
142 case Comment::ParamCommandCommentKind: {
150 Params.push_back(PCC);
154 case Comment::TParamCommandCommentKind: {
162 TParams.push_back(TPCC);
166 case Comment::VerbatimBlockCommentKind:
167 MiscBlocks.push_back(cast<BlockCommandComment>(Child));
170 case Comment::VerbatimLineCommentKind: {
173 if (!Info->IsDeclarationCommand)
174 MiscBlocks.push_back(VLC);
178 case Comment::TextCommentKind:
179 case Comment::InlineCommandCommentKind:
180 case Comment::HTMLStartTagCommentKind:
181 case Comment::HTMLEndTagCommentKind:
182 case Comment::VerbatimBlockLineCommentKind:
183 case Comment::FullCommentKind:
184 llvm_unreachable(
"AST node of this kind can't be a child of " 192 std::stable_sort(Params.begin(), Params.end(),
193 ParamCommandCommentCompareIndex());
195 std::stable_sort(TParams.begin(), TParams.end(),
196 TParamCommandCommentComparePosition());
200 llvm::raw_svector_ostream &Result) {
204 for (
unsigned i = 0, e = C->
getNumAttrs(); i != e; i++) {
208 if (!Attr.
Value.empty())
209 Result <<
"=\"" << Attr.
Value <<
"\"";
219 class CommentASTToHTMLConverter :
226 FC(FC), Result(Str), Traits(Traits)
252 void appendToResultWithHTMLEscaping(StringRef S);
257 llvm::raw_svector_ostream Result;
263 void CommentASTToHTMLConverter::visitTextComment(
const TextComment *C) {
264 appendToResultWithHTMLEscaping(C->
getText());
267 void CommentASTToHTMLConverter::visitInlineCommandComment(
279 case InlineCommandComment::RenderNormal:
280 for (
unsigned i = 0, e = C->
getNumArgs(); i != e; ++i) {
281 appendToResultWithHTMLEscaping(C->
getArgText(i));
286 case InlineCommandComment::RenderBold:
289 appendToResultWithHTMLEscaping(Arg0);
292 case InlineCommandComment::RenderMonospaced:
295 appendToResultWithHTMLEscaping(Arg0);
298 case InlineCommandComment::RenderEmphasized:
301 appendToResultWithHTMLEscaping(Arg0);
307 void CommentASTToHTMLConverter::visitHTMLStartTagComment(
309 printHTMLStartTagComment(C, Result);
312 void CommentASTToHTMLConverter::visitHTMLEndTagComment(
317 void CommentASTToHTMLConverter::visitParagraphComment(
330 void CommentASTToHTMLConverter::visitBlockCommandComment(
334 Result <<
"<p class=\"para-brief\">";
340 Result <<
"<p class=\"para-returns\">" 341 "<span class=\"word-returns\">Returns</span> ";
350 void CommentASTToHTMLConverter::visitParamCommandComment(
354 Result <<
"<dt class=\"param-name-index-vararg\">";
357 Result <<
"<dt class=\"param-name-index-" 363 Result <<
"<dt class=\"param-name-index-invalid\">";
370 Result <<
"<dd class=\"param-descr-index-vararg\">";
372 Result <<
"<dd class=\"param-descr-index-" 376 Result <<
"<dd class=\"param-descr-index-invalid\">";
382 void CommentASTToHTMLConverter::visitTParamCommandComment(
386 Result <<
"<dt class=\"tparam-name-index-" 390 Result <<
"<dt class=\"tparam-name-index-other\">";
393 Result <<
"<dt class=\"tparam-name-index-invalid\">";
401 Result <<
"<dd class=\"tparam-descr-index-" 405 Result <<
"<dd class=\"tparam-descr-index-other\">";
407 Result <<
"<dd class=\"tparam-descr-index-invalid\">";
413 void CommentASTToHTMLConverter::visitVerbatimBlockComment(
420 for (
unsigned i = 0; i != NumLines; ++i) {
421 appendToResultWithHTMLEscaping(C->
getText(i));
422 if (i + 1 != NumLines)
428 void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
430 llvm_unreachable(
"should not see this AST node");
433 void CommentASTToHTMLConverter::visitVerbatimLineComment(
436 appendToResultWithHTMLEscaping(C->
getText());
440 void CommentASTToHTMLConverter::visitFullComment(
const FullComment *C) {
441 FullCommentParts Parts(C, Traits);
443 bool FirstParagraphIsBrief =
false;
444 if (Parts.Headerfile)
445 visit(Parts.Headerfile);
448 else if (Parts.FirstParagraph) {
449 Result <<
"<p class=\"para-brief\">";
450 visitNonStandaloneParagraphComment(Parts.FirstParagraph);
452 FirstParagraphIsBrief =
true;
455 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
456 const Comment *C = Parts.MiscBlocks[i];
457 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
462 if (Parts.TParams.size() != 0) {
464 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
465 visit(Parts.TParams[i]);
469 if (Parts.Params.size() != 0) {
471 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
472 visit(Parts.Params[i]);
476 if (Parts.Returns.size() != 0) {
477 Result <<
"<div class=\"result-discussion\">";
478 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
479 visit(Parts.Returns[i]);
485 void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
496 void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
497 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
526 class CommentASTToXMLConverter :
534 FC(FC), Result(Str), Traits(Traits), SM(SM) { }
558 void appendToResultWithXMLEscaping(StringRef S);
559 void appendToResultWithCDATAEscaping(StringRef S);
561 void formatTextOfDeclaration(
const DeclInfo *DI,
568 llvm::raw_svector_ostream Result;
574 void getSourceTextOfDeclaration(
const DeclInfo *ThisDecl,
578 llvm::raw_svector_ostream
OS(Str);
580 PPolicy.PolishForDeclaration =
true;
581 PPolicy.TerseOutput =
true;
582 PPolicy.ConstantsAsWritten =
true;
587 void CommentASTToXMLConverter::formatTextOfDeclaration(
590 StringRef StringDecl(Declaration.c_str(), Declaration.size());
594 unsigned Length = Declaration.size();
601 if (static_cast<bool>(FormattedStringDecl)) {
602 Declaration = *FormattedStringDecl;
608 void CommentASTToXMLConverter::visitTextComment(
const TextComment *C) {
609 appendToResultWithXMLEscaping(C->
getText());
612 void CommentASTToXMLConverter::visitInlineCommandComment(
624 case InlineCommandComment::RenderNormal:
625 for (
unsigned i = 0, e = C->
getNumArgs(); i != e; ++i) {
626 appendToResultWithXMLEscaping(C->
getArgText(i));
630 case InlineCommandComment::RenderBold:
633 appendToResultWithXMLEscaping(Arg0);
636 case InlineCommandComment::RenderMonospaced:
638 Result <<
"<monospaced>";
639 appendToResultWithXMLEscaping(Arg0);
640 Result <<
"</monospaced>";
642 case InlineCommandComment::RenderEmphasized:
644 Result <<
"<emphasized>";
645 appendToResultWithXMLEscaping(Arg0);
646 Result <<
"</emphasized>";
651 void CommentASTToXMLConverter::visitHTMLStartTagComment(
653 Result <<
"<rawHTML";
655 Result <<
" isMalformed=\"1\"";
660 llvm::raw_svector_ostream TagOS(Tag);
661 printHTMLStartTagComment(C, TagOS);
663 appendToResultWithCDATAEscaping(Tag);
665 Result <<
"</rawHTML>";
670 Result <<
"<rawHTML";
672 Result <<
" isMalformed=\"1\"";
673 Result <<
"></" << C->
getTagName() <<
"></rawHTML>";
677 CommentASTToXMLConverter::visitParagraphComment(
const ParagraphComment *C) {
678 appendParagraphCommentWithKind(C, StringRef());
681 void CommentASTToXMLConverter::appendParagraphCommentWithKind(
683 StringRef ParagraphKind) {
687 if (ParagraphKind.empty())
690 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
699 void CommentASTToXMLConverter::visitBlockCommandComment(
701 StringRef ParagraphKind;
704 case CommandTraits::KCI_attention:
705 case CommandTraits::KCI_author:
706 case CommandTraits::KCI_authors:
707 case CommandTraits::KCI_bug:
708 case CommandTraits::KCI_copyright:
709 case CommandTraits::KCI_date:
710 case CommandTraits::KCI_invariant:
711 case CommandTraits::KCI_note:
712 case CommandTraits::KCI_post:
713 case CommandTraits::KCI_pre:
714 case CommandTraits::KCI_remark:
715 case CommandTraits::KCI_remarks:
716 case CommandTraits::KCI_sa:
717 case CommandTraits::KCI_see:
718 case CommandTraits::KCI_since:
719 case CommandTraits::KCI_todo:
720 case CommandTraits::KCI_version:
721 case CommandTraits::KCI_warning:
728 appendParagraphCommentWithKind(C->
getParagraph(), ParagraphKind);
731 void CommentASTToXMLConverter::visitParamCommandComment(
733 Result <<
"<Parameter><Name>";
741 Result <<
"<IsVarArg />";
748 case ParamCommandComment::In:
751 case ParamCommandComment::Out:
754 case ParamCommandComment::InOut:
758 Result <<
"</Direction><Discussion>";
760 Result <<
"</Discussion></Parameter>";
763 void CommentASTToXMLConverter::visitTParamCommandComment(
765 Result <<
"<Parameter><Name>";
771 Result <<
"<Index>" << C->
getIndex(0) <<
"</Index>";
774 Result <<
"<Discussion>";
776 Result <<
"</Discussion></Parameter>";
779 void CommentASTToXMLConverter::visitVerbatimBlockComment(
786 case CommandTraits::KCI_code:
787 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
790 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
793 for (
unsigned i = 0; i != NumLines; ++i) {
794 appendToResultWithXMLEscaping(C->
getText(i));
795 if (i + 1 != NumLines)
798 Result <<
"</Verbatim>";
801 void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
803 llvm_unreachable(
"should not see this AST node");
806 void CommentASTToXMLConverter::visitVerbatimLineComment(
808 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
809 appendToResultWithXMLEscaping(C->
getText());
810 Result <<
"</Verbatim>";
813 void CommentASTToXMLConverter::visitFullComment(
const FullComment *C) {
814 FullCommentParts Parts(C, Traits);
817 StringRef RootEndTag;
820 case DeclInfo::OtherKind:
821 RootEndTag =
"</Other>";
824 case DeclInfo::FunctionKind:
825 RootEndTag =
"</Function>";
826 Result <<
"<Function";
828 case DeclInfo::NotTemplate:
830 case DeclInfo::Template:
831 Result <<
" templateKind=\"template\"";
834 Result <<
" templateKind=\"specialization\"";
837 llvm_unreachable(
"partial specializations of functions " 838 "are not allowed in C++");
841 Result <<
" isInstanceMethod=\"1\"";
843 Result <<
" isClassMethod=\"1\"";
845 case DeclInfo::ClassKind:
846 RootEndTag =
"</Class>";
849 case DeclInfo::NotTemplate:
851 case DeclInfo::Template:
852 Result <<
" templateKind=\"template\"";
855 Result <<
" templateKind=\"specialization\"";
858 Result <<
" templateKind=\"partialSpecialization\"";
862 case DeclInfo::VariableKind:
863 RootEndTag =
"</Variable>";
864 Result <<
"<Variable";
866 case DeclInfo::NamespaceKind:
867 RootEndTag =
"</Namespace>";
868 Result <<
"<Namespace";
870 case DeclInfo::TypedefKind:
871 RootEndTag =
"</Typedef>";
872 Result <<
"<Typedef";
874 case DeclInfo::EnumKind:
875 RootEndTag =
"</Enum>";
884 FileID FID = LocInfo.first;
885 unsigned FileOffset = LocInfo.second;
889 Result <<
" file=\"";
890 appendToResultWithXMLEscaping(FE->getName());
902 bool FoundName =
false;
906 std::string Name = DeclName.getAsString();
907 appendToResultWithXMLEscaping(Name);
913 Result <<
"<Name><anonymous></Name>";
921 appendToResultWithXMLEscaping(USR);
927 RootEndTag =
"</Other>";
928 Result <<
"<Other><Name>unknown</Name>";
931 if (Parts.Headerfile) {
932 Result <<
"<Headerfile>";
933 visit(Parts.Headerfile);
934 Result <<
"</Headerfile>";
939 Result <<
"<Declaration>";
941 getSourceTextOfDeclaration(DI, Declaration);
942 formatTextOfDeclaration(DI, Declaration);
943 appendToResultWithXMLEscaping(Declaration);
944 Result <<
"</Declaration>";
947 bool FirstParagraphIsBrief =
false;
949 Result <<
"<Abstract>";
951 Result <<
"</Abstract>";
952 }
else if (Parts.FirstParagraph) {
953 Result <<
"<Abstract>";
954 visit(Parts.FirstParagraph);
955 Result <<
"</Abstract>";
956 FirstParagraphIsBrief =
true;
959 if (Parts.TParams.size() != 0) {
960 Result <<
"<TemplateParameters>";
961 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
962 visit(Parts.TParams[i]);
963 Result <<
"</TemplateParameters>";
966 if (Parts.Params.size() != 0) {
967 Result <<
"<Parameters>";
968 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
969 visit(Parts.Params[i]);
970 Result <<
"</Parameters>";
973 if (Parts.Exceptions.size() != 0) {
974 Result <<
"<Exceptions>";
975 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
976 visit(Parts.Exceptions[i]);
977 Result <<
"</Exceptions>";
980 if (Parts.Returns.size() != 0) {
981 Result <<
"<ResultDiscussion>";
982 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
983 visit(Parts.Returns[i]);
984 Result <<
"</ResultDiscussion>";
989 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
990 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
992 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
993 if (DA->getMessage().empty())
994 Result <<
"<Deprecated/>";
996 Result <<
"<Deprecated>";
997 appendToResultWithXMLEscaping(DA->getMessage());
998 Result <<
"</Deprecated>";
1001 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1002 if (UA->getMessage().empty())
1003 Result <<
"<Unavailable/>";
1005 Result <<
"<Unavailable>";
1006 appendToResultWithXMLEscaping(UA->getMessage());
1007 Result <<
"</Unavailable>";
1014 Result <<
"<Availability";
1015 StringRef Distribution;
1016 if (AA->getPlatform()) {
1017 Distribution = AvailabilityAttr::getPrettyPlatformName(
1018 AA->getPlatform()->getName());
1019 if (Distribution.empty())
1020 Distribution = AA->getPlatform()->getName();
1022 Result <<
" distribution=\"" << Distribution <<
"\">";
1023 VersionTuple IntroducedInVersion = AA->getIntroduced();
1024 if (!IntroducedInVersion.empty()) {
1025 Result <<
"<IntroducedInVersion>" 1026 << IntroducedInVersion.getAsString()
1027 <<
"</IntroducedInVersion>";
1029 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1030 if (!DeprecatedInVersion.empty()) {
1031 Result <<
"<DeprecatedInVersion>" 1032 << DeprecatedInVersion.getAsString()
1033 <<
"</DeprecatedInVersion>";
1035 VersionTuple RemovedAfterVersion = AA->getObsoleted();
1036 if (!RemovedAfterVersion.empty()) {
1037 Result <<
"<RemovedAfterVersion>" 1038 << RemovedAfterVersion.getAsString()
1039 <<
"</RemovedAfterVersion>";
1041 StringRef DeprecationSummary = AA->getMessage();
1042 if (!DeprecationSummary.empty()) {
1043 Result <<
"<DeprecationSummary>";
1044 appendToResultWithXMLEscaping(DeprecationSummary);
1045 Result <<
"</DeprecationSummary>";
1047 if (AA->getUnavailable())
1048 Result <<
"<Unavailable/>";
1049 Result <<
"</Availability>";
1054 bool StartTagEmitted =
false;
1055 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1056 const Comment *C = Parts.MiscBlocks[i];
1057 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1059 if (!StartTagEmitted) {
1060 Result <<
"<Discussion>";
1061 StartTagEmitted =
true;
1065 if (StartTagEmitted)
1066 Result <<
"</Discussion>";
1069 Result << RootEndTag;
1072 void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1073 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
1098 void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1102 Result <<
"<![CDATA[";
1103 while (!S.empty()) {
1104 size_t Pos = S.find(
"]]>");
1106 Result <<
"]]]]><![CDATA[>";
1107 S = S.drop_front(3);
1110 if (Pos == StringRef::npos)
1113 Result << S.substr(0, Pos);
1115 S = S.drop_front(Pos);
1126 CommentASTToHTMLConverter Converter(FC, HTML,
1128 Converter.visit(FC);
1134 CommentASTToHTMLConverter Converter(
nullptr, Text,
1136 Converter.visit(HTC);
1144 Converter.visit(FC);
Defines the clang::ASTContext interface.
unsigned getColumnNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Return the column # for the specified file position.
Describes how types, statements, expressions, and declarations should be printed. ...
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
comments::CommandTraits & getCommentCommandTraits() const
Encodes a location in the source.
ASTContext & getASTContext() const LLVM_READONLY
Cached information about one file (either on disk or in the virtual file system). ...
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Dataflow Directional Tag Classes.
The name of a declaration.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
SourceManager & getSourceManager()
bool generateUSRForDecl(const Decl *D, SmallVectorImpl< char > &Buf)
Generate a USR for a Decl, including the USR prefix.
This represents a decl that may have a name.
const LangOptions & getLangOpts() const
This class handles loading and caching of source files into memory.
Attr - This represents one attribute.
SourceLocation getLocation() const
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.