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) {
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(
275 case InlineCommandComment::RenderNormal:
282 case InlineCommandComment::RenderBold:
285 appendToResultWithHTMLEscaping(Arg0);
288 case InlineCommandComment::RenderMonospaced:
291 appendToResultWithHTMLEscaping(Arg0);
294 case InlineCommandComment::RenderEmphasized:
297 appendToResultWithHTMLEscaping(Arg0);
303 void CommentASTToHTMLConverter::visitHTMLStartTagComment(
305 printHTMLStartTagComment(C, Result);
308 void CommentASTToHTMLConverter::visitHTMLEndTagComment(
313 void CommentASTToHTMLConverter::visitParagraphComment(
326 void CommentASTToHTMLConverter::visitBlockCommandComment(
330 Result <<
"<p class=\"para-brief\">";
336 Result <<
"<p class=\"para-returns\">" 337 "<span class=\"word-returns\">Returns</span> ";
346 void CommentASTToHTMLConverter::visitParamCommandComment(
350 Result <<
"<dt class=\"param-name-index-vararg\">";
353 Result <<
"<dt class=\"param-name-index-" 359 Result <<
"<dt class=\"param-name-index-invalid\">";
366 Result <<
"<dd class=\"param-descr-index-vararg\">";
368 Result <<
"<dd class=\"param-descr-index-" 372 Result <<
"<dd class=\"param-descr-index-invalid\">";
378 void CommentASTToHTMLConverter::visitTParamCommandComment(
382 Result <<
"<dt class=\"tparam-name-index-" 386 Result <<
"<dt class=\"tparam-name-index-other\">";
389 Result <<
"<dt class=\"tparam-name-index-invalid\">";
397 Result <<
"<dd class=\"tparam-descr-index-" 401 Result <<
"<dd class=\"tparam-descr-index-other\">";
403 Result <<
"<dd class=\"tparam-descr-index-invalid\">";
409 void CommentASTToHTMLConverter::visitVerbatimBlockComment(
416 for (
unsigned i = 0;
i != NumLines; ++
i) {
417 appendToResultWithHTMLEscaping(C->
getText(
i));
418 if (
i + 1 != NumLines)
424 void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
426 llvm_unreachable(
"should not see this AST node");
429 void CommentASTToHTMLConverter::visitVerbatimLineComment(
432 appendToResultWithHTMLEscaping(C->
getText());
436 void CommentASTToHTMLConverter::visitFullComment(
const FullComment *C) {
437 FullCommentParts Parts(C, Traits);
439 bool FirstParagraphIsBrief =
false;
440 if (Parts.Headerfile)
441 visit(Parts.Headerfile);
444 else if (Parts.FirstParagraph) {
445 Result <<
"<p class=\"para-brief\">";
446 visitNonStandaloneParagraphComment(Parts.FirstParagraph);
448 FirstParagraphIsBrief =
true;
451 for (
unsigned i = 0, e = Parts.MiscBlocks.size();
i != e; ++
i) {
452 const Comment *C = Parts.MiscBlocks[
i];
453 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
458 if (Parts.TParams.size() != 0) {
460 for (
unsigned i = 0, e = Parts.TParams.size();
i != e; ++
i)
461 visit(Parts.TParams[
i]);
465 if (Parts.Params.size() != 0) {
467 for (
unsigned i = 0, e = Parts.Params.size();
i != e; ++
i)
468 visit(Parts.Params[
i]);
472 if (Parts.Returns.size() != 0) {
473 Result <<
"<div class=\"result-discussion\">";
474 for (
unsigned i = 0, e = Parts.Returns.size();
i != e; ++
i)
475 visit(Parts.Returns[
i]);
481 void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
492 void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
493 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
522 class CommentASTToXMLConverter :
530 FC(FC), Result(Str), Traits(Traits), SM(SM) { }
554 void appendToResultWithXMLEscaping(StringRef S);
555 void appendToResultWithCDATAEscaping(StringRef S);
557 void formatTextOfDeclaration(
const DeclInfo *DI,
564 llvm::raw_svector_ostream Result;
570 void getSourceTextOfDeclaration(
const DeclInfo *ThisDecl,
574 llvm::raw_svector_ostream
OS(Str);
576 PPolicy.PolishForDeclaration =
true;
577 PPolicy.TerseOutput =
true;
578 PPolicy.ConstantsAsWritten =
true;
583 void CommentASTToXMLConverter::formatTextOfDeclaration(
586 StringRef StringDecl(Declaration.c_str(), Declaration.size());
590 unsigned Length = Declaration.size();
593 Style.FixNamespaceComments =
false;
597 if (static_cast<bool>(FormattedStringDecl)) {
598 Declaration = *FormattedStringDecl;
604 void CommentASTToXMLConverter::visitTextComment(
const TextComment *C) {
605 appendToResultWithXMLEscaping(C->
getText());
608 void CommentASTToXMLConverter::visitInlineCommandComment(
620 case InlineCommandComment::RenderNormal:
626 case InlineCommandComment::RenderBold:
629 appendToResultWithXMLEscaping(Arg0);
632 case InlineCommandComment::RenderMonospaced:
634 Result <<
"<monospaced>";
635 appendToResultWithXMLEscaping(Arg0);
636 Result <<
"</monospaced>";
638 case InlineCommandComment::RenderEmphasized:
640 Result <<
"<emphasized>";
641 appendToResultWithXMLEscaping(Arg0);
642 Result <<
"</emphasized>";
647 void CommentASTToXMLConverter::visitHTMLStartTagComment(
649 Result <<
"<rawHTML";
651 Result <<
" isMalformed=\"1\"";
656 llvm::raw_svector_ostream TagOS(Tag);
657 printHTMLStartTagComment(C, TagOS);
659 appendToResultWithCDATAEscaping(Tag);
661 Result <<
"</rawHTML>";
666 Result <<
"<rawHTML";
668 Result <<
" isMalformed=\"1\"";
669 Result <<
"></" << C->
getTagName() <<
"></rawHTML>";
673 CommentASTToXMLConverter::visitParagraphComment(
const ParagraphComment *C) {
674 appendParagraphCommentWithKind(C, StringRef());
677 void CommentASTToXMLConverter::appendParagraphCommentWithKind(
679 StringRef ParagraphKind) {
683 if (ParagraphKind.empty())
686 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
695 void CommentASTToXMLConverter::visitBlockCommandComment(
697 StringRef ParagraphKind;
700 case CommandTraits::KCI_attention:
701 case CommandTraits::KCI_author:
702 case CommandTraits::KCI_authors:
703 case CommandTraits::KCI_bug:
704 case CommandTraits::KCI_copyright:
705 case CommandTraits::KCI_date:
706 case CommandTraits::KCI_invariant:
707 case CommandTraits::KCI_note:
708 case CommandTraits::KCI_post:
709 case CommandTraits::KCI_pre:
710 case CommandTraits::KCI_remark:
711 case CommandTraits::KCI_remarks:
712 case CommandTraits::KCI_sa:
713 case CommandTraits::KCI_see:
714 case CommandTraits::KCI_since:
715 case CommandTraits::KCI_todo:
716 case CommandTraits::KCI_version:
717 case CommandTraits::KCI_warning:
724 appendParagraphCommentWithKind(C->
getParagraph(), ParagraphKind);
727 void CommentASTToXMLConverter::visitParamCommandComment(
729 Result <<
"<Parameter><Name>";
737 Result <<
"<IsVarArg />";
744 case ParamCommandComment::In:
747 case ParamCommandComment::Out:
750 case ParamCommandComment::InOut:
754 Result <<
"</Direction><Discussion>";
756 Result <<
"</Discussion></Parameter>";
759 void CommentASTToXMLConverter::visitTParamCommandComment(
761 Result <<
"<Parameter><Name>";
767 Result <<
"<Index>" << C->
getIndex(0) <<
"</Index>";
770 Result <<
"<Discussion>";
772 Result <<
"</Discussion></Parameter>";
775 void CommentASTToXMLConverter::visitVerbatimBlockComment(
782 case CommandTraits::KCI_code:
783 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
786 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
789 for (
unsigned i = 0;
i != NumLines; ++
i) {
790 appendToResultWithXMLEscaping(C->
getText(
i));
791 if (
i + 1 != NumLines)
794 Result <<
"</Verbatim>";
797 void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
799 llvm_unreachable(
"should not see this AST node");
802 void CommentASTToXMLConverter::visitVerbatimLineComment(
804 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
805 appendToResultWithXMLEscaping(C->
getText());
806 Result <<
"</Verbatim>";
809 void CommentASTToXMLConverter::visitFullComment(
const FullComment *C) {
810 FullCommentParts Parts(C, Traits);
813 StringRef RootEndTag;
816 case DeclInfo::OtherKind:
817 RootEndTag =
"</Other>";
820 case DeclInfo::FunctionKind:
821 RootEndTag =
"</Function>";
822 Result <<
"<Function";
824 case DeclInfo::NotTemplate:
826 case DeclInfo::Template:
827 Result <<
" templateKind=\"template\"";
830 Result <<
" templateKind=\"specialization\"";
833 llvm_unreachable(
"partial specializations of functions " 834 "are not allowed in C++");
837 Result <<
" isInstanceMethod=\"1\"";
839 Result <<
" isClassMethod=\"1\"";
841 case DeclInfo::ClassKind:
842 RootEndTag =
"</Class>";
845 case DeclInfo::NotTemplate:
847 case DeclInfo::Template:
848 Result <<
" templateKind=\"template\"";
851 Result <<
" templateKind=\"specialization\"";
854 Result <<
" templateKind=\"partialSpecialization\"";
858 case DeclInfo::VariableKind:
859 RootEndTag =
"</Variable>";
860 Result <<
"<Variable";
862 case DeclInfo::NamespaceKind:
863 RootEndTag =
"</Namespace>";
864 Result <<
"<Namespace";
866 case DeclInfo::TypedefKind:
867 RootEndTag =
"</Typedef>";
868 Result <<
"<Typedef";
870 case DeclInfo::EnumKind:
871 RootEndTag =
"</Enum>";
880 FileID FID = LocInfo.first;
881 unsigned FileOffset = LocInfo.second;
885 Result <<
" file=\"";
886 appendToResultWithXMLEscaping(FE->getName());
898 bool FoundName =
false;
902 std::string Name = DeclName.getAsString();
903 appendToResultWithXMLEscaping(Name);
909 Result <<
"<Name><anonymous></Name>";
917 appendToResultWithXMLEscaping(USR);
923 RootEndTag =
"</Other>";
924 Result <<
"<Other><Name>unknown</Name>";
927 if (Parts.Headerfile) {
928 Result <<
"<Headerfile>";
929 visit(Parts.Headerfile);
930 Result <<
"</Headerfile>";
935 Result <<
"<Declaration>";
937 getSourceTextOfDeclaration(DI, Declaration);
938 formatTextOfDeclaration(DI, Declaration);
939 appendToResultWithXMLEscaping(Declaration);
940 Result <<
"</Declaration>";
943 bool FirstParagraphIsBrief =
false;
945 Result <<
"<Abstract>";
947 Result <<
"</Abstract>";
948 }
else if (Parts.FirstParagraph) {
949 Result <<
"<Abstract>";
950 visit(Parts.FirstParagraph);
951 Result <<
"</Abstract>";
952 FirstParagraphIsBrief =
true;
955 if (Parts.TParams.size() != 0) {
956 Result <<
"<TemplateParameters>";
957 for (
unsigned i = 0, e = Parts.TParams.size();
i != e; ++
i)
958 visit(Parts.TParams[
i]);
959 Result <<
"</TemplateParameters>";
962 if (Parts.Params.size() != 0) {
963 Result <<
"<Parameters>";
964 for (
unsigned i = 0, e = Parts.Params.size();
i != e; ++
i)
965 visit(Parts.Params[
i]);
966 Result <<
"</Parameters>";
969 if (Parts.Exceptions.size() != 0) {
970 Result <<
"<Exceptions>";
971 for (
unsigned i = 0, e = Parts.Exceptions.size();
i != e; ++
i)
972 visit(Parts.Exceptions[
i]);
973 Result <<
"</Exceptions>";
976 if (Parts.Returns.size() != 0) {
977 Result <<
"<ResultDiscussion>";
978 for (
unsigned i = 0, e = Parts.Returns.size();
i != e; ++
i)
979 visit(Parts.Returns[
i]);
980 Result <<
"</ResultDiscussion>";
985 for (
unsigned i = 0, e = Attrs.size();
i != e;
i++) {
986 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[
i]);
988 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[
i])) {
989 if (DA->getMessage().empty())
990 Result <<
"<Deprecated/>";
992 Result <<
"<Deprecated>";
993 appendToResultWithXMLEscaping(DA->getMessage());
994 Result <<
"</Deprecated>";
997 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
998 if (UA->getMessage().empty())
999 Result <<
"<Unavailable/>";
1001 Result <<
"<Unavailable>";
1002 appendToResultWithXMLEscaping(UA->getMessage());
1003 Result <<
"</Unavailable>";
1010 Result <<
"<Availability";
1011 StringRef Distribution;
1012 if (AA->getPlatform()) {
1013 Distribution = AvailabilityAttr::getPrettyPlatformName(
1014 AA->getPlatform()->getName());
1015 if (Distribution.empty())
1016 Distribution = AA->getPlatform()->getName();
1018 Result <<
" distribution=\"" << Distribution <<
"\">";
1019 VersionTuple IntroducedInVersion = AA->getIntroduced();
1020 if (!IntroducedInVersion.empty()) {
1021 Result <<
"<IntroducedInVersion>" 1022 << IntroducedInVersion.getAsString()
1023 <<
"</IntroducedInVersion>";
1025 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1026 if (!DeprecatedInVersion.empty()) {
1027 Result <<
"<DeprecatedInVersion>" 1028 << DeprecatedInVersion.getAsString()
1029 <<
"</DeprecatedInVersion>";
1031 VersionTuple RemovedAfterVersion = AA->getObsoleted();
1032 if (!RemovedAfterVersion.empty()) {
1033 Result <<
"<RemovedAfterVersion>" 1034 << RemovedAfterVersion.getAsString()
1035 <<
"</RemovedAfterVersion>";
1037 StringRef DeprecationSummary = AA->getMessage();
1038 if (!DeprecationSummary.empty()) {
1039 Result <<
"<DeprecationSummary>";
1040 appendToResultWithXMLEscaping(DeprecationSummary);
1041 Result <<
"</DeprecationSummary>";
1043 if (AA->getUnavailable())
1044 Result <<
"<Unavailable/>";
1045 Result <<
"</Availability>";
1050 bool StartTagEmitted =
false;
1051 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++
i) {
1052 const Comment *C = Parts.MiscBlocks[
i];
1053 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1055 if (!StartTagEmitted) {
1056 Result <<
"<Discussion>";
1057 StartTagEmitted =
true;
1061 if (StartTagEmitted)
1062 Result <<
"</Discussion>";
1065 Result << RootEndTag;
1068 void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1069 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
1094 void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1098 Result <<
"<![CDATA[";
1099 while (!S.empty()) {
1100 size_t Pos = S.find(
"]]>");
1102 Result <<
"]]]]><![CDATA[>";
1103 S = S.drop_front(3);
1106 if (Pos == StringRef::npos)
1109 Result << S.substr(0, Pos);
1111 S = S.drop_front(Pos);
1122 CommentASTToHTMLConverter Converter(FC, HTML,
1124 Converter.visit(FC);
1130 CommentASTToHTMLConverter Converter(
nullptr, Text,
1132 Converter.visit(HTC);
1140 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.