16 #include "llvm/ADT/StringExtras.h" 17 #include "llvm/ADT/TinyPtrVector.h" 18 #include "llvm/Support/raw_ostream.h" 20 using namespace clang;
28 class ParamCommandCommentCompareIndex {
47 return LHSIndex < RHSIndex;
55 class TParamCommandCommentComparePosition {
80 struct FullCommentParts {
91 llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
95 FullCommentParts::FullCommentParts(
const FullComment *C,
97 Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
104 case Comment::NoCommentKind:
107 case Comment::ParagraphCommentKind: {
114 MiscBlocks.push_back(PC);
118 case Comment::BlockCommandCommentKind: {
121 if (!Brief && Info->IsBriefCommand) {
125 if (!Headerfile && Info->IsHeaderfileCommand) {
129 if (Info->IsReturnsCommand) {
130 Returns.push_back(BCC);
133 if (Info->IsThrowsCommand) {
134 Exceptions.push_back(BCC);
137 MiscBlocks.push_back(BCC);
141 case Comment::ParamCommandCommentKind: {
149 Params.push_back(PCC);
153 case Comment::TParamCommandCommentKind: {
161 TParams.push_back(TPCC);
165 case Comment::VerbatimBlockCommentKind:
166 MiscBlocks.push_back(cast<BlockCommandComment>(Child));
169 case Comment::VerbatimLineCommentKind: {
172 if (!Info->IsDeclarationCommand)
173 MiscBlocks.push_back(VLC);
177 case Comment::TextCommentKind:
178 case Comment::InlineCommandCommentKind:
179 case Comment::HTMLStartTagCommentKind:
180 case Comment::HTMLEndTagCommentKind:
181 case Comment::VerbatimBlockLineCommentKind:
182 case Comment::FullCommentKind:
183 llvm_unreachable(
"AST node of this kind can't be a child of " 191 llvm::stable_sort(Params, ParamCommandCommentCompareIndex());
192 llvm::stable_sort(TParams, TParamCommandCommentComparePosition());
196 llvm::raw_svector_ostream &Result) {
200 for (
unsigned i = 0, e = C->
getNumAttrs(); i != e; i++) {
204 if (!Attr.
Value.empty())
205 Result <<
"=\"" << Attr.
Value <<
"\"";
215 class CommentASTToHTMLConverter :
222 FC(FC), Result(Str), Traits(Traits)
248 void appendToResultWithHTMLEscaping(StringRef S);
253 llvm::raw_svector_ostream Result;
259 void CommentASTToHTMLConverter::visitTextComment(
const TextComment *C) {
260 appendToResultWithHTMLEscaping(C->
getText());
263 void CommentASTToHTMLConverter::visitInlineCommandComment(
276 for (
unsigned i = 0, e = C->
getNumArgs(); i != e; ++i) {
277 appendToResultWithHTMLEscaping(C->
getArgText(i));
285 appendToResultWithHTMLEscaping(Arg0);
291 appendToResultWithHTMLEscaping(Arg0);
297 appendToResultWithHTMLEscaping(Arg0);
302 Result <<
"<span id=\"" << Arg0 <<
"\"></span>";
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();
597 Style.FixNamespaceComments =
false;
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>";
648 case InlineCommandComment::RenderAnchor:
650 Result <<
"<anchor id=\"" << Arg0 <<
"\"></anchor>";
655 void CommentASTToXMLConverter::visitHTMLStartTagComment(
657 Result <<
"<rawHTML";
659 Result <<
" isMalformed=\"1\"";
664 llvm::raw_svector_ostream TagOS(Tag);
665 printHTMLStartTagComment(C, TagOS);
667 appendToResultWithCDATAEscaping(Tag);
669 Result <<
"</rawHTML>";
674 Result <<
"<rawHTML";
676 Result <<
" isMalformed=\"1\"";
677 Result <<
"></" << C->
getTagName() <<
"></rawHTML>";
681 CommentASTToXMLConverter::visitParagraphComment(
const ParagraphComment *C) {
682 appendParagraphCommentWithKind(C, StringRef());
685 void CommentASTToXMLConverter::appendParagraphCommentWithKind(
687 StringRef ParagraphKind) {
691 if (ParagraphKind.empty())
694 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
703 void CommentASTToXMLConverter::visitBlockCommandComment(
705 StringRef ParagraphKind;
708 case CommandTraits::KCI_attention:
709 case CommandTraits::KCI_author:
710 case CommandTraits::KCI_authors:
711 case CommandTraits::KCI_bug:
712 case CommandTraits::KCI_copyright:
713 case CommandTraits::KCI_date:
714 case CommandTraits::KCI_invariant:
715 case CommandTraits::KCI_note:
716 case CommandTraits::KCI_post:
717 case CommandTraits::KCI_pre:
718 case CommandTraits::KCI_remark:
719 case CommandTraits::KCI_remarks:
720 case CommandTraits::KCI_sa:
721 case CommandTraits::KCI_see:
722 case CommandTraits::KCI_since:
723 case CommandTraits::KCI_todo:
724 case CommandTraits::KCI_version:
725 case CommandTraits::KCI_warning:
732 appendParagraphCommentWithKind(C->
getParagraph(), ParagraphKind);
735 void CommentASTToXMLConverter::visitParamCommandComment(
737 Result <<
"<Parameter><Name>";
745 Result <<
"<IsVarArg />";
752 case ParamCommandComment::In:
755 case ParamCommandComment::Out:
758 case ParamCommandComment::InOut:
762 Result <<
"</Direction><Discussion>";
764 Result <<
"</Discussion></Parameter>";
767 void CommentASTToXMLConverter::visitTParamCommandComment(
769 Result <<
"<Parameter><Name>";
775 Result <<
"<Index>" << C->
getIndex(0) <<
"</Index>";
778 Result <<
"<Discussion>";
780 Result <<
"</Discussion></Parameter>";
783 void CommentASTToXMLConverter::visitVerbatimBlockComment(
790 case CommandTraits::KCI_code:
791 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
794 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
797 for (
unsigned i = 0; i != NumLines; ++i) {
798 appendToResultWithXMLEscaping(C->
getText(i));
799 if (i + 1 != NumLines)
802 Result <<
"</Verbatim>";
805 void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
807 llvm_unreachable(
"should not see this AST node");
810 void CommentASTToXMLConverter::visitVerbatimLineComment(
812 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
813 appendToResultWithXMLEscaping(C->
getText());
814 Result <<
"</Verbatim>";
817 void CommentASTToXMLConverter::visitFullComment(
const FullComment *C) {
818 FullCommentParts Parts(C, Traits);
821 StringRef RootEndTag;
824 case DeclInfo::OtherKind:
825 RootEndTag =
"</Other>";
828 case DeclInfo::FunctionKind:
829 RootEndTag =
"</Function>";
830 Result <<
"<Function";
832 case DeclInfo::NotTemplate:
834 case DeclInfo::Template:
835 Result <<
" templateKind=\"template\"";
837 case DeclInfo::TemplateSpecialization:
838 Result <<
" templateKind=\"specialization\"";
840 case DeclInfo::TemplatePartialSpecialization:
841 llvm_unreachable(
"partial specializations of functions " 842 "are not allowed in C++");
845 Result <<
" isInstanceMethod=\"1\"";
847 Result <<
" isClassMethod=\"1\"";
849 case DeclInfo::ClassKind:
850 RootEndTag =
"</Class>";
853 case DeclInfo::NotTemplate:
855 case DeclInfo::Template:
856 Result <<
" templateKind=\"template\"";
858 case DeclInfo::TemplateSpecialization:
859 Result <<
" templateKind=\"specialization\"";
861 case DeclInfo::TemplatePartialSpecialization:
862 Result <<
" templateKind=\"partialSpecialization\"";
866 case DeclInfo::VariableKind:
867 RootEndTag =
"</Variable>";
868 Result <<
"<Variable";
870 case DeclInfo::NamespaceKind:
871 RootEndTag =
"</Namespace>";
872 Result <<
"<Namespace";
874 case DeclInfo::TypedefKind:
875 RootEndTag =
"</Typedef>";
876 Result <<
"<Typedef";
878 case DeclInfo::EnumKind:
879 RootEndTag =
"</Enum>";
888 FileID FID = LocInfo.first;
889 unsigned FileOffset = LocInfo.second;
893 Result <<
" file=\"";
894 appendToResultWithXMLEscaping(FE->getName());
906 bool FoundName =
false;
910 std::string Name = DeclName.getAsString();
911 appendToResultWithXMLEscaping(Name);
917 Result <<
"<Name><anonymous></Name>";
925 appendToResultWithXMLEscaping(USR);
931 RootEndTag =
"</Other>";
932 Result <<
"<Other><Name>unknown</Name>";
935 if (Parts.Headerfile) {
936 Result <<
"<Headerfile>";
937 visit(Parts.Headerfile);
938 Result <<
"</Headerfile>";
943 Result <<
"<Declaration>";
945 getSourceTextOfDeclaration(DI, Declaration);
946 formatTextOfDeclaration(DI, Declaration);
947 appendToResultWithXMLEscaping(Declaration);
948 Result <<
"</Declaration>";
951 bool FirstParagraphIsBrief =
false;
953 Result <<
"<Abstract>";
955 Result <<
"</Abstract>";
956 }
else if (Parts.FirstParagraph) {
957 Result <<
"<Abstract>";
958 visit(Parts.FirstParagraph);
959 Result <<
"</Abstract>";
960 FirstParagraphIsBrief =
true;
963 if (Parts.TParams.size() != 0) {
964 Result <<
"<TemplateParameters>";
965 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
966 visit(Parts.TParams[i]);
967 Result <<
"</TemplateParameters>";
970 if (Parts.Params.size() != 0) {
971 Result <<
"<Parameters>";
972 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
973 visit(Parts.Params[i]);
974 Result <<
"</Parameters>";
977 if (Parts.Exceptions.size() != 0) {
978 Result <<
"<Exceptions>";
979 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
980 visit(Parts.Exceptions[i]);
981 Result <<
"</Exceptions>";
984 if (Parts.Returns.size() != 0) {
985 Result <<
"<ResultDiscussion>";
986 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
987 visit(Parts.Returns[i]);
988 Result <<
"</ResultDiscussion>";
993 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
994 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
996 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
997 if (DA->getMessage().empty())
998 Result <<
"<Deprecated/>";
1000 Result <<
"<Deprecated>";
1001 appendToResultWithXMLEscaping(DA->getMessage());
1002 Result <<
"</Deprecated>";
1005 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1006 if (UA->getMessage().empty())
1007 Result <<
"<Unavailable/>";
1009 Result <<
"<Unavailable>";
1010 appendToResultWithXMLEscaping(UA->getMessage());
1011 Result <<
"</Unavailable>";
1018 Result <<
"<Availability";
1019 StringRef Distribution;
1020 if (AA->getPlatform()) {
1021 Distribution = AvailabilityAttr::getPrettyPlatformName(
1022 AA->getPlatform()->getName());
1023 if (Distribution.empty())
1024 Distribution = AA->getPlatform()->getName();
1026 Result <<
" distribution=\"" << Distribution <<
"\">";
1027 VersionTuple IntroducedInVersion = AA->getIntroduced();
1028 if (!IntroducedInVersion.empty()) {
1029 Result <<
"<IntroducedInVersion>" 1030 << IntroducedInVersion.getAsString()
1031 <<
"</IntroducedInVersion>";
1033 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1034 if (!DeprecatedInVersion.empty()) {
1035 Result <<
"<DeprecatedInVersion>" 1036 << DeprecatedInVersion.getAsString()
1037 <<
"</DeprecatedInVersion>";
1039 VersionTuple RemovedAfterVersion = AA->getObsoleted();
1040 if (!RemovedAfterVersion.empty()) {
1041 Result <<
"<RemovedAfterVersion>" 1042 << RemovedAfterVersion.getAsString()
1043 <<
"</RemovedAfterVersion>";
1045 StringRef DeprecationSummary = AA->getMessage();
1046 if (!DeprecationSummary.empty()) {
1047 Result <<
"<DeprecationSummary>";
1048 appendToResultWithXMLEscaping(DeprecationSummary);
1049 Result <<
"</DeprecationSummary>";
1051 if (AA->getUnavailable())
1052 Result <<
"<Unavailable/>";
1053 Result <<
"</Availability>";
1058 bool StartTagEmitted =
false;
1059 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1060 const Comment *C = Parts.MiscBlocks[i];
1061 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1063 if (!StartTagEmitted) {
1064 Result <<
"<Discussion>";
1065 StartTagEmitted =
true;
1069 if (StartTagEmitted)
1070 Result <<
"</Discussion>";
1073 Result << RootEndTag;
1076 void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1077 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
1102 void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1106 Result <<
"<![CDATA[";
1107 while (!S.empty()) {
1108 size_t Pos = S.find(
"]]>");
1110 Result <<
"]]]]><![CDATA[>";
1111 S = S.drop_front(3);
1114 if (Pos == StringRef::npos)
1117 Result << S.substr(0, Pos);
1119 S = S.drop_front(Pos);
1124 CommentToXMLConverter::CommentToXMLConverter() {}
1125 CommentToXMLConverter::~CommentToXMLConverter() {}
1127 void CommentToXMLConverter::convertCommentToHTML(
const FullComment *FC,
1130 CommentASTToHTMLConverter Converter(FC, HTML,
1132 Converter.visit(FC);
1135 void CommentToXMLConverter::convertHTMLTagNodeToText(
1138 CommentASTToHTMLConverter Converter(
nullptr, Text,
1140 Converter.visit(HTC);
1143 void CommentToXMLConverter::convertCommentToXML(
const FullComment *FC,
1148 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.