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:
727 appendParagraphCommentWithKind(C->
getParagraph(), ParagraphKind);
730 void CommentASTToXMLConverter::visitParamCommandComment(
732 Result <<
"<Parameter><Name>";
740 Result <<
"<IsVarArg />";
747 case ParamCommandComment::In:
750 case ParamCommandComment::Out:
753 case ParamCommandComment::InOut:
757 Result <<
"</Direction><Discussion>";
759 Result <<
"</Discussion></Parameter>";
762 void CommentASTToXMLConverter::visitTParamCommandComment(
764 Result <<
"<Parameter><Name>";
770 Result <<
"<Index>" << C->
getIndex(0) <<
"</Index>";
773 Result <<
"<Discussion>";
775 Result <<
"</Discussion></Parameter>";
778 void CommentASTToXMLConverter::visitVerbatimBlockComment(
785 case CommandTraits::KCI_code:
786 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
789 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
792 for (
unsigned i = 0; i != NumLines; ++i) {
793 appendToResultWithXMLEscaping(C->
getText(i));
794 if (i + 1 != NumLines)
797 Result <<
"</Verbatim>";
800 void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
802 llvm_unreachable(
"should not see this AST node");
805 void CommentASTToXMLConverter::visitVerbatimLineComment(
807 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
808 appendToResultWithXMLEscaping(C->
getText());
809 Result <<
"</Verbatim>";
812 void CommentASTToXMLConverter::visitFullComment(
const FullComment *C) {
813 FullCommentParts Parts(C, Traits);
816 StringRef RootEndTag;
819 case DeclInfo::OtherKind:
820 RootEndTag =
"</Other>";
823 case DeclInfo::FunctionKind:
824 RootEndTag =
"</Function>";
825 Result <<
"<Function";
827 case DeclInfo::NotTemplate:
829 case DeclInfo::Template:
830 Result <<
" templateKind=\"template\"";
833 Result <<
" templateKind=\"specialization\"";
836 llvm_unreachable(
"partial specializations of functions " 837 "are not allowed in C++");
840 Result <<
" isInstanceMethod=\"1\"";
842 Result <<
" isClassMethod=\"1\"";
844 case DeclInfo::ClassKind:
845 RootEndTag =
"</Class>";
848 case DeclInfo::NotTemplate:
850 case DeclInfo::Template:
851 Result <<
" templateKind=\"template\"";
854 Result <<
" templateKind=\"specialization\"";
857 Result <<
" templateKind=\"partialSpecialization\"";
861 case DeclInfo::VariableKind:
862 RootEndTag =
"</Variable>";
863 Result <<
"<Variable";
865 case DeclInfo::NamespaceKind:
866 RootEndTag =
"</Namespace>";
867 Result <<
"<Namespace";
869 case DeclInfo::TypedefKind:
870 RootEndTag =
"</Typedef>";
871 Result <<
"<Typedef";
873 case DeclInfo::EnumKind:
874 RootEndTag =
"</Enum>";
883 FileID FID = LocInfo.first;
884 unsigned FileOffset = LocInfo.second;
888 Result <<
" file=\"";
889 appendToResultWithXMLEscaping(FE->getName());
901 bool FoundName =
false;
905 std::string Name = DeclName.getAsString();
906 appendToResultWithXMLEscaping(Name);
912 Result <<
"<Name><anonymous></Name>";
920 appendToResultWithXMLEscaping(USR);
926 RootEndTag =
"</Other>";
927 Result <<
"<Other><Name>unknown</Name>";
930 if (Parts.Headerfile) {
931 Result <<
"<Headerfile>";
932 visit(Parts.Headerfile);
933 Result <<
"</Headerfile>";
938 Result <<
"<Declaration>";
940 getSourceTextOfDeclaration(DI, Declaration);
941 formatTextOfDeclaration(DI, Declaration);
942 appendToResultWithXMLEscaping(Declaration);
943 Result <<
"</Declaration>";
946 bool FirstParagraphIsBrief =
false;
948 Result <<
"<Abstract>";
950 Result <<
"</Abstract>";
951 }
else if (Parts.FirstParagraph) {
952 Result <<
"<Abstract>";
953 visit(Parts.FirstParagraph);
954 Result <<
"</Abstract>";
955 FirstParagraphIsBrief =
true;
958 if (Parts.TParams.size() != 0) {
959 Result <<
"<TemplateParameters>";
960 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
961 visit(Parts.TParams[i]);
962 Result <<
"</TemplateParameters>";
965 if (Parts.Params.size() != 0) {
966 Result <<
"<Parameters>";
967 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
968 visit(Parts.Params[i]);
969 Result <<
"</Parameters>";
972 if (Parts.Exceptions.size() != 0) {
973 Result <<
"<Exceptions>";
974 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
975 visit(Parts.Exceptions[i]);
976 Result <<
"</Exceptions>";
979 if (Parts.Returns.size() != 0) {
980 Result <<
"<ResultDiscussion>";
981 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
982 visit(Parts.Returns[i]);
983 Result <<
"</ResultDiscussion>";
988 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
989 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
991 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
992 if (DA->getMessage().empty())
993 Result <<
"<Deprecated/>";
995 Result <<
"<Deprecated>";
996 appendToResultWithXMLEscaping(DA->getMessage());
997 Result <<
"</Deprecated>";
1000 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1001 if (UA->getMessage().empty())
1002 Result <<
"<Unavailable/>";
1004 Result <<
"<Unavailable>";
1005 appendToResultWithXMLEscaping(UA->getMessage());
1006 Result <<
"</Unavailable>";
1013 Result <<
"<Availability";
1014 StringRef Distribution;
1015 if (AA->getPlatform()) {
1016 Distribution = AvailabilityAttr::getPrettyPlatformName(
1017 AA->getPlatform()->getName());
1018 if (Distribution.empty())
1019 Distribution = AA->getPlatform()->getName();
1021 Result <<
" distribution=\"" << Distribution <<
"\">";
1022 VersionTuple IntroducedInVersion = AA->getIntroduced();
1023 if (!IntroducedInVersion.empty()) {
1024 Result <<
"<IntroducedInVersion>" 1025 << IntroducedInVersion.getAsString()
1026 <<
"</IntroducedInVersion>";
1028 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1029 if (!DeprecatedInVersion.empty()) {
1030 Result <<
"<DeprecatedInVersion>" 1031 << DeprecatedInVersion.getAsString()
1032 <<
"</DeprecatedInVersion>";
1034 VersionTuple RemovedAfterVersion = AA->getObsoleted();
1035 if (!RemovedAfterVersion.empty()) {
1036 Result <<
"<RemovedAfterVersion>" 1037 << RemovedAfterVersion.getAsString()
1038 <<
"</RemovedAfterVersion>";
1040 StringRef DeprecationSummary = AA->getMessage();
1041 if (!DeprecationSummary.empty()) {
1042 Result <<
"<DeprecationSummary>";
1043 appendToResultWithXMLEscaping(DeprecationSummary);
1044 Result <<
"</DeprecationSummary>";
1046 if (AA->getUnavailable())
1047 Result <<
"<Unavailable/>";
1048 Result <<
"</Availability>";
1053 bool StartTagEmitted =
false;
1054 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1055 const Comment *C = Parts.MiscBlocks[i];
1056 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1058 if (!StartTagEmitted) {
1059 Result <<
"<Discussion>";
1060 StartTagEmitted =
true;
1064 if (StartTagEmitted)
1065 Result <<
"</Discussion>";
1068 Result << RootEndTag;
1071 void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1072 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
1097 void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1101 Result <<
"<![CDATA[";
1102 while (!S.empty()) {
1103 size_t Pos = S.find(
"]]>");
1105 Result <<
"]]]]><![CDATA[>";
1106 S = S.drop_front(3);
1109 if (Pos == StringRef::npos)
1112 Result << S.substr(0, Pos);
1114 S = S.drop_front(Pos);
1125 CommentASTToHTMLConverter Converter(FC, HTML,
1127 Converter.visit(FC);
1133 CommentASTToHTMLConverter Converter(
nullptr, Text,
1135 Converter.visit(HTC);
1143 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.
DeclarationName - The name of a declaration.
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.