18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/ADT/TinyPtrVector.h"
20 #include "llvm/Support/raw_ostream.h"
22 using namespace clang;
23 using namespace clang::comments;
24 using namespace clang::index;
30 class ParamCommandCommentCompareIndex {
49 return LHSIndex < RHSIndex;
57 class TParamCommandCommentComparePosition {
82 struct FullCommentParts {
93 llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
99 Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
109 case Comment::ParagraphCommentKind: {
116 MiscBlocks.push_back(PC);
120 case Comment::BlockCommandCommentKind: {
123 if (!Brief && Info->IsBriefCommand) {
127 if (!Headerfile && Info->IsHeaderfileCommand) {
131 if (Info->IsReturnsCommand) {
132 Returns.push_back(BCC);
135 if (Info->IsThrowsCommand) {
136 Exceptions.push_back(BCC);
139 MiscBlocks.push_back(BCC);
143 case Comment::ParamCommandCommentKind: {
151 Params.push_back(PCC);
155 case Comment::TParamCommandCommentKind: {
163 TParams.push_back(TPCC);
167 case Comment::VerbatimBlockCommentKind:
168 MiscBlocks.push_back(cast<BlockCommandComment>(Child));
171 case Comment::VerbatimLineCommentKind: {
174 if (!Info->IsDeclarationCommand)
175 MiscBlocks.push_back(VLC);
179 case Comment::TextCommentKind:
180 case Comment::InlineCommandCommentKind:
181 case Comment::HTMLStartTagCommentKind:
182 case Comment::HTMLEndTagCommentKind:
183 case Comment::VerbatimBlockLineCommentKind:
184 case Comment::FullCommentKind:
185 llvm_unreachable(
"AST node of this kind can't be a child of "
193 std::stable_sort(Params.begin(), Params.end(),
194 ParamCommandCommentCompareIndex());
196 std::stable_sort(TParams.begin(), TParams.end(),
197 TParamCommandCommentComparePosition());
201 llvm::raw_svector_ostream &Result) {
205 for (
unsigned i = 0, e = C->
getNumAttrs(); i != e; i++) {
209 if (!Attr.
Value.empty())
210 Result <<
"=\"" << Attr.
Value <<
"\"";
220 class CommentASTToHTMLConverter :
227 FC(FC), Result(Str), Traits(Traits)
253 void appendToResultWithHTMLEscaping(StringRef
S);
258 llvm::raw_svector_ostream Result;
264 void CommentASTToHTMLConverter::visitTextComment(
const TextComment *C) {
265 appendToResultWithHTMLEscaping(C->
getText());
268 void CommentASTToHTMLConverter::visitInlineCommandComment(
281 for (
unsigned i = 0, e = C->
getNumArgs(); i != e; ++i) {
282 appendToResultWithHTMLEscaping(C->
getArgText(i));
290 appendToResultWithHTMLEscaping(Arg0);
296 appendToResultWithHTMLEscaping(Arg0);
302 appendToResultWithHTMLEscaping(Arg0);
308 void CommentASTToHTMLConverter::visitHTMLStartTagComment(
310 printHTMLStartTagComment(C, Result);
313 void CommentASTToHTMLConverter::visitHTMLEndTagComment(
318 void CommentASTToHTMLConverter::visitParagraphComment(
331 void CommentASTToHTMLConverter::visitBlockCommandComment(
335 Result <<
"<p class=\"para-brief\">";
341 Result <<
"<p class=\"para-returns\">"
342 "<span class=\"word-returns\">Returns</span> ";
351 void CommentASTToHTMLConverter::visitParamCommandComment(
355 Result <<
"<dt class=\"param-name-index-vararg\">";
358 Result <<
"<dt class=\"param-name-index-"
364 Result <<
"<dt class=\"param-name-index-invalid\">";
371 Result <<
"<dd class=\"param-descr-index-vararg\">";
373 Result <<
"<dd class=\"param-descr-index-"
377 Result <<
"<dd class=\"param-descr-index-invalid\">";
383 void CommentASTToHTMLConverter::visitTParamCommandComment(
387 Result <<
"<dt class=\"tparam-name-index-"
391 Result <<
"<dt class=\"tparam-name-index-other\">";
394 Result <<
"<dt class=\"tparam-name-index-invalid\">";
402 Result <<
"<dd class=\"tparam-descr-index-"
406 Result <<
"<dd class=\"tparam-descr-index-other\">";
408 Result <<
"<dd class=\"tparam-descr-index-invalid\">";
414 void CommentASTToHTMLConverter::visitVerbatimBlockComment(
421 for (
unsigned i = 0; i != NumLines; ++i) {
422 appendToResultWithHTMLEscaping(C->
getText(i));
423 if (i + 1 != NumLines)
429 void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
431 llvm_unreachable(
"should not see this AST node");
434 void CommentASTToHTMLConverter::visitVerbatimLineComment(
437 appendToResultWithHTMLEscaping(C->
getText());
441 void CommentASTToHTMLConverter::visitFullComment(
const FullComment *C) {
442 FullCommentParts Parts(C, Traits);
444 bool FirstParagraphIsBrief =
false;
445 if (Parts.Headerfile)
446 visit(Parts.Headerfile);
449 else if (Parts.FirstParagraph) {
450 Result <<
"<p class=\"para-brief\">";
451 visitNonStandaloneParagraphComment(Parts.FirstParagraph);
453 FirstParagraphIsBrief =
true;
456 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
457 const Comment *C = Parts.MiscBlocks[i];
458 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
463 if (Parts.TParams.size() != 0) {
465 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
466 visit(Parts.TParams[i]);
470 if (Parts.Params.size() != 0) {
472 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
473 visit(Parts.Params[i]);
477 if (Parts.Returns.size() != 0) {
478 Result <<
"<div class=\"result-discussion\">";
479 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
480 visit(Parts.Returns[i]);
487 void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
498 void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef
S) {
499 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
528 class CommentASTToXMLConverter :
538 FC(FC), Result(Str), Traits(Traits), SM(SM),
539 FormatRewriterContext(SFC),
540 FormatInMemoryUniqueId(FUID) { }
564 void appendToResultWithXMLEscaping(StringRef S);
565 void appendToResultWithCDATAEscaping(StringRef S);
567 void formatTextOfDeclaration(
const DeclInfo *DI,
574 llvm::raw_svector_ostream Result;
579 unsigned FormatInMemoryUniqueId;
582 void getSourceTextOfDeclaration(
const DeclInfo *ThisDecl,
586 llvm::raw_svector_ostream OS(Str);
588 PPolicy.PolishForDeclaration =
true;
589 PPolicy.TerseOutput =
true;
594 void CommentASTToXMLConverter::formatTextOfDeclaration(
598 std::string StringDecl = Declaration.str();
603 filename +=
"xmldecl";
604 filename += llvm::utostr(FormatInMemoryUniqueId);
606 FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
607 SourceLocation Start = FormatRewriterContext.Sources.getLocForStartOfFile(ID)
609 unsigned Length = Declaration.size();
615 Declaration = FormatRewriterContext.getRewrittenText(ID);
620 void CommentASTToXMLConverter::visitTextComment(
const TextComment *C) {
621 appendToResultWithXMLEscaping(C->
getText());
624 void CommentASTToXMLConverter::visitInlineCommandComment(
637 for (
unsigned i = 0, e = C->
getNumArgs(); i != e; ++i) {
638 appendToResultWithXMLEscaping(C->
getArgText(i));
645 appendToResultWithXMLEscaping(Arg0);
650 Result <<
"<monospaced>";
651 appendToResultWithXMLEscaping(Arg0);
652 Result <<
"</monospaced>";
656 Result <<
"<emphasized>";
657 appendToResultWithXMLEscaping(Arg0);
658 Result <<
"</emphasized>";
663 void CommentASTToXMLConverter::visitHTMLStartTagComment(
665 Result <<
"<rawHTML";
667 Result <<
" isMalformed=\"1\"";
672 llvm::raw_svector_ostream TagOS(Tag);
673 printHTMLStartTagComment(C, TagOS);
675 appendToResultWithCDATAEscaping(Tag);
677 Result <<
"</rawHTML>";
682 Result <<
"<rawHTML";
684 Result <<
" isMalformed=\"1\"";
685 Result <<
"></" << C->
getTagName() <<
"></rawHTML>";
689 CommentASTToXMLConverter::visitParagraphComment(
const ParagraphComment *C) {
690 appendParagraphCommentWithKind(C, StringRef());
693 void CommentASTToXMLConverter::appendParagraphCommentWithKind(
695 StringRef ParagraphKind) {
699 if (ParagraphKind.empty())
702 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
711 void CommentASTToXMLConverter::visitBlockCommandComment(
713 StringRef ParagraphKind;
716 case CommandTraits::KCI_attention:
717 case CommandTraits::KCI_author:
718 case CommandTraits::KCI_authors:
719 case CommandTraits::KCI_bug:
720 case CommandTraits::KCI_copyright:
721 case CommandTraits::KCI_date:
722 case CommandTraits::KCI_invariant:
723 case CommandTraits::KCI_note:
724 case CommandTraits::KCI_post:
725 case CommandTraits::KCI_pre:
726 case CommandTraits::KCI_remark:
727 case CommandTraits::KCI_remarks:
728 case CommandTraits::KCI_sa:
729 case CommandTraits::KCI_see:
730 case CommandTraits::KCI_since:
731 case CommandTraits::KCI_todo:
732 case CommandTraits::KCI_version:
733 case CommandTraits::KCI_warning:
739 appendParagraphCommentWithKind(C->
getParagraph(), ParagraphKind);
742 void CommentASTToXMLConverter::visitParamCommandComment(
744 Result <<
"<Parameter><Name>";
752 Result <<
"<IsVarArg />";
769 Result <<
"</Direction><Discussion>";
771 Result <<
"</Discussion></Parameter>";
774 void CommentASTToXMLConverter::visitTParamCommandComment(
776 Result <<
"<Parameter><Name>";
782 Result <<
"<Index>" << C->
getIndex(0) <<
"</Index>";
785 Result <<
"<Discussion>";
787 Result <<
"</Discussion></Parameter>";
790 void CommentASTToXMLConverter::visitVerbatimBlockComment(
797 case CommandTraits::KCI_code:
798 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
801 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
804 for (
unsigned i = 0; i != NumLines; ++i) {
805 appendToResultWithXMLEscaping(C->
getText(i));
806 if (i + 1 != NumLines)
809 Result <<
"</Verbatim>";
812 void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
814 llvm_unreachable(
"should not see this AST node");
817 void CommentASTToXMLConverter::visitVerbatimLineComment(
819 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
820 appendToResultWithXMLEscaping(C->
getText());
821 Result <<
"</Verbatim>";
824 void CommentASTToXMLConverter::visitFullComment(
const FullComment *C) {
825 FullCommentParts Parts(C, Traits);
828 StringRef RootEndTag;
832 RootEndTag =
"</Other>";
836 RootEndTag =
"</Function>";
837 Result <<
"<Function";
842 Result <<
" templateKind=\"template\"";
845 Result <<
" templateKind=\"specialization\"";
848 llvm_unreachable(
"partial specializations of functions "
849 "are not allowed in C++");
852 Result <<
" isInstanceMethod=\"1\"";
854 Result <<
" isClassMethod=\"1\"";
857 RootEndTag =
"</Class>";
863 Result <<
" templateKind=\"template\"";
866 Result <<
" templateKind=\"specialization\"";
869 Result <<
" templateKind=\"partialSpecialization\"";
874 RootEndTag =
"</Variable>";
875 Result <<
"<Variable";
878 RootEndTag =
"</Namespace>";
879 Result <<
"<Namespace";
882 RootEndTag =
"</Typedef>";
883 Result <<
"<Typedef";
886 RootEndTag =
"</Enum>";
895 FileID FID = LocInfo.first;
896 unsigned FileOffset = LocInfo.second;
900 Result <<
" file=\"";
901 appendToResultWithXMLEscaping(FE->getName());
913 bool FoundName =
false;
917 std::string Name = DeclName.getAsString();
918 appendToResultWithXMLEscaping(Name);
924 Result <<
"<Name><anonymous></Name>";
932 appendToResultWithXMLEscaping(USR);
938 RootEndTag =
"</Other>";
939 Result <<
"<Other><Name>unknown</Name>";
942 if (Parts.Headerfile) {
943 Result <<
"<Headerfile>";
944 visit(Parts.Headerfile);
945 Result <<
"</Headerfile>";
950 Result <<
"<Declaration>";
952 getSourceTextOfDeclaration(DI, Declaration);
953 formatTextOfDeclaration(DI, Declaration);
954 appendToResultWithXMLEscaping(Declaration);
955 Result <<
"</Declaration>";
958 bool FirstParagraphIsBrief =
false;
960 Result <<
"<Abstract>";
962 Result <<
"</Abstract>";
963 }
else if (Parts.FirstParagraph) {
964 Result <<
"<Abstract>";
965 visit(Parts.FirstParagraph);
966 Result <<
"</Abstract>";
967 FirstParagraphIsBrief =
true;
970 if (Parts.TParams.size() != 0) {
971 Result <<
"<TemplateParameters>";
972 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
973 visit(Parts.TParams[i]);
974 Result <<
"</TemplateParameters>";
977 if (Parts.Params.size() != 0) {
978 Result <<
"<Parameters>";
979 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
980 visit(Parts.Params[i]);
981 Result <<
"</Parameters>";
984 if (Parts.Exceptions.size() != 0) {
985 Result <<
"<Exceptions>";
986 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
987 visit(Parts.Exceptions[i]);
988 Result <<
"</Exceptions>";
991 if (Parts.Returns.size() != 0) {
992 Result <<
"<ResultDiscussion>";
993 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
994 visit(Parts.Returns[i]);
995 Result <<
"</ResultDiscussion>";
1000 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
1001 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
1003 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
1004 if (DA->getMessage().empty())
1005 Result <<
"<Deprecated/>";
1007 Result <<
"<Deprecated>";
1008 appendToResultWithXMLEscaping(DA->getMessage());
1009 Result <<
"</Deprecated>";
1012 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1013 if (UA->getMessage().empty())
1014 Result <<
"<Unavailable/>";
1016 Result <<
"<Unavailable>";
1017 appendToResultWithXMLEscaping(UA->getMessage());
1018 Result <<
"</Unavailable>";
1025 Result <<
"<Availability";
1026 StringRef Distribution;
1027 if (AA->getPlatform()) {
1028 Distribution = AvailabilityAttr::getPrettyPlatformName(
1029 AA->getPlatform()->getName());
1030 if (Distribution.empty())
1031 Distribution = AA->getPlatform()->getName();
1033 Result <<
" distribution=\"" << Distribution <<
"\">";
1034 VersionTuple IntroducedInVersion = AA->getIntroduced();
1035 if (!IntroducedInVersion.
empty()) {
1036 Result <<
"<IntroducedInVersion>"
1038 <<
"</IntroducedInVersion>";
1040 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1041 if (!DeprecatedInVersion.
empty()) {
1042 Result <<
"<DeprecatedInVersion>"
1044 <<
"</DeprecatedInVersion>";
1047 if (!RemovedAfterVersion.
empty()) {
1048 Result <<
"<RemovedAfterVersion>"
1050 <<
"</RemovedAfterVersion>";
1052 StringRef DeprecationSummary = AA->getMessage();
1053 if (!DeprecationSummary.empty()) {
1054 Result <<
"<DeprecationSummary>";
1055 appendToResultWithXMLEscaping(DeprecationSummary);
1056 Result <<
"</DeprecationSummary>";
1058 if (AA->getUnavailable())
1059 Result <<
"<Unavailable/>";
1060 Result <<
"</Availability>";
1065 bool StartTagEmitted =
false;
1066 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1067 const Comment *C = Parts.MiscBlocks[i];
1068 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1070 if (!StartTagEmitted) {
1071 Result <<
"<Discussion>";
1072 StartTagEmitted =
true;
1076 if (StartTagEmitted)
1077 Result <<
"</Discussion>";
1080 Result << RootEndTag;
1085 void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1086 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
1111 void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1115 Result <<
"<![CDATA[";
1116 while (!S.empty()) {
1117 size_t Pos = S.find(
"]]>");
1119 Result <<
"]]]]><![CDATA[>";
1120 S = S.drop_front(3);
1123 if (Pos == StringRef::npos)
1126 Result << S.substr(0, Pos);
1128 S = S.drop_front(Pos);
1133 CommentToXMLConverter::CommentToXMLConverter() : FormatInMemoryUniqueId(0) {}
1139 CommentASTToHTMLConverter Converter(FC, HTML,
1141 Converter.visit(FC);
1147 CommentASTToHTMLConverter Converter(
nullptr, Text,
1149 Converter.visit(HTC);
1155 if (!FormatContext || (FormatInMemoryUniqueId % 1000) == 0) {
1163 FormatInMemoryUniqueId++);
1164 Converter.visit(FC);
Defines the clang::ASTContext interface.
Represents a version number in the form major[.minor[.subminor[.build]]].
Defines a utility class for use of clang-format in libclang.
Describes how types, statements, expressions, and declarations should be printed. ...
A small class to be used by libclang clients to format a declaration string in memory. This object is instantiated once and used each time a formatting is needed.
comments::CommandTraits & getCommentCommandTraits() 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...
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
std::string getAsString() const
Retrieve a string representation of the version number.
const LangOptions & getLangOpts() const
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
ID
Defines the set of possible language-specific address spaces.
unsigned getColumnNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Return the column # for the specified file position.
static CharSourceRange getCharRange(SourceRange R)
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
ASTContext & getASTContext() const LLVM_READONLY
Cached information about one file (either on disk or in the virtual file system). ...
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool empty() const
Determine whether this version information is empty (e.g., all version components are zero)...
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
SourceManager & getSourceManager()
bool generateUSRForDecl(const Decl *D, SmallVectorImpl< char > &Buf)
Generate a USR for a Decl, including the USR prefix.
SourceLocation getLocation() const
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
This class handles loading and caching of source files into memory.
Attr - This represents one attribute.