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;
97 FullCommentParts::FullCommentParts(
const FullComment *C,
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]);
486 void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
497 void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef
S) {
527 class CommentASTToXMLConverter :
537 FC(FC), Result(Str), Traits(Traits), SM(SM),
538 FormatRewriterContext(SFC),
539 FormatInMemoryUniqueId(FUID) { }
563 void appendToResultWithXMLEscaping(StringRef S);
564 void appendToResultWithCDATAEscaping(StringRef S);
566 void formatTextOfDeclaration(
const DeclInfo *DI,
573 llvm::raw_svector_ostream Result;
578 unsigned FormatInMemoryUniqueId;
581 void getSourceTextOfDeclaration(
const DeclInfo *ThisDecl,
585 llvm::raw_svector_ostream OS(Str);
587 PPolicy.PolishForDeclaration =
true;
588 PPolicy.TerseOutput =
true;
593 void CommentASTToXMLConverter::formatTextOfDeclaration(
596 StringRef StringDecl(Declaration.c_str(), Declaration.size());
601 filename +=
"xmldecl";
602 filename += llvm::utostr(FormatInMemoryUniqueId);
604 FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
605 SourceLocation Start = FormatRewriterContext.Sources.getLocForStartOfFile(ID)
607 unsigned Length = Declaration.size();
613 Declaration = FormatRewriterContext.getRewrittenText(ID);
618 void CommentASTToXMLConverter::visitTextComment(
const TextComment *C) {
619 appendToResultWithXMLEscaping(C->
getText());
622 void CommentASTToXMLConverter::visitInlineCommandComment(
635 for (
unsigned i = 0, e = C->
getNumArgs(); i != e; ++i) {
636 appendToResultWithXMLEscaping(C->
getArgText(i));
643 appendToResultWithXMLEscaping(Arg0);
648 Result <<
"<monospaced>";
649 appendToResultWithXMLEscaping(Arg0);
650 Result <<
"</monospaced>";
654 Result <<
"<emphasized>";
655 appendToResultWithXMLEscaping(Arg0);
656 Result <<
"</emphasized>";
661 void CommentASTToXMLConverter::visitHTMLStartTagComment(
663 Result <<
"<rawHTML";
665 Result <<
" isMalformed=\"1\"";
670 llvm::raw_svector_ostream TagOS(Tag);
671 printHTMLStartTagComment(C, TagOS);
673 appendToResultWithCDATAEscaping(Tag);
675 Result <<
"</rawHTML>";
680 Result <<
"<rawHTML";
682 Result <<
" isMalformed=\"1\"";
683 Result <<
"></" << C->
getTagName() <<
"></rawHTML>";
687 CommentASTToXMLConverter::visitParagraphComment(
const ParagraphComment *C) {
688 appendParagraphCommentWithKind(C, StringRef());
691 void CommentASTToXMLConverter::appendParagraphCommentWithKind(
693 StringRef ParagraphKind) {
697 if (ParagraphKind.empty())
700 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
709 void CommentASTToXMLConverter::visitBlockCommandComment(
711 StringRef ParagraphKind;
714 case CommandTraits::KCI_attention:
715 case CommandTraits::KCI_author:
716 case CommandTraits::KCI_authors:
717 case CommandTraits::KCI_bug:
718 case CommandTraits::KCI_copyright:
719 case CommandTraits::KCI_date:
720 case CommandTraits::KCI_invariant:
721 case CommandTraits::KCI_note:
722 case CommandTraits::KCI_post:
723 case CommandTraits::KCI_pre:
724 case CommandTraits::KCI_remark:
725 case CommandTraits::KCI_remarks:
726 case CommandTraits::KCI_sa:
727 case CommandTraits::KCI_see:
728 case CommandTraits::KCI_since:
729 case CommandTraits::KCI_todo:
730 case CommandTraits::KCI_version:
731 case CommandTraits::KCI_warning:
737 appendParagraphCommentWithKind(C->
getParagraph(), ParagraphKind);
740 void CommentASTToXMLConverter::visitParamCommandComment(
742 Result <<
"<Parameter><Name>";
750 Result <<
"<IsVarArg />";
767 Result <<
"</Direction><Discussion>";
769 Result <<
"</Discussion></Parameter>";
772 void CommentASTToXMLConverter::visitTParamCommandComment(
774 Result <<
"<Parameter><Name>";
780 Result <<
"<Index>" << C->
getIndex(0) <<
"</Index>";
783 Result <<
"<Discussion>";
785 Result <<
"</Discussion></Parameter>";
788 void CommentASTToXMLConverter::visitVerbatimBlockComment(
795 case CommandTraits::KCI_code:
796 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
799 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
802 for (
unsigned i = 0; i != NumLines; ++i) {
803 appendToResultWithXMLEscaping(C->
getText(i));
804 if (i + 1 != NumLines)
807 Result <<
"</Verbatim>";
810 void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
812 llvm_unreachable(
"should not see this AST node");
815 void CommentASTToXMLConverter::visitVerbatimLineComment(
817 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
818 appendToResultWithXMLEscaping(C->
getText());
819 Result <<
"</Verbatim>";
822 void CommentASTToXMLConverter::visitFullComment(
const FullComment *C) {
823 FullCommentParts Parts(C, Traits);
826 StringRef RootEndTag;
830 RootEndTag =
"</Other>";
834 RootEndTag =
"</Function>";
835 Result <<
"<Function";
840 Result <<
" templateKind=\"template\"";
843 Result <<
" templateKind=\"specialization\"";
846 llvm_unreachable(
"partial specializations of functions "
847 "are not allowed in C++");
850 Result <<
" isInstanceMethod=\"1\"";
852 Result <<
" isClassMethod=\"1\"";
855 RootEndTag =
"</Class>";
861 Result <<
" templateKind=\"template\"";
864 Result <<
" templateKind=\"specialization\"";
867 Result <<
" templateKind=\"partialSpecialization\"";
872 RootEndTag =
"</Variable>";
873 Result <<
"<Variable";
876 RootEndTag =
"</Namespace>";
877 Result <<
"<Namespace";
880 RootEndTag =
"</Typedef>";
881 Result <<
"<Typedef";
884 RootEndTag =
"</Enum>";
893 FileID FID = LocInfo.first;
894 unsigned FileOffset = LocInfo.second;
898 Result <<
" file=\"";
899 appendToResultWithXMLEscaping(FE->getName());
911 bool FoundName =
false;
915 std::string
Name = DeclName.getAsString();
916 appendToResultWithXMLEscaping(Name);
922 Result <<
"<Name><anonymous></Name>";
930 appendToResultWithXMLEscaping(USR);
936 RootEndTag =
"</Other>";
937 Result <<
"<Other><Name>unknown</Name>";
940 if (Parts.Headerfile) {
941 Result <<
"<Headerfile>";
942 visit(Parts.Headerfile);
943 Result <<
"</Headerfile>";
948 Result <<
"<Declaration>";
950 getSourceTextOfDeclaration(DI, Declaration);
951 formatTextOfDeclaration(DI, Declaration);
952 appendToResultWithXMLEscaping(Declaration);
953 Result <<
"</Declaration>";
956 bool FirstParagraphIsBrief =
false;
958 Result <<
"<Abstract>";
960 Result <<
"</Abstract>";
961 }
else if (Parts.FirstParagraph) {
962 Result <<
"<Abstract>";
963 visit(Parts.FirstParagraph);
964 Result <<
"</Abstract>";
965 FirstParagraphIsBrief =
true;
968 if (Parts.TParams.size() != 0) {
969 Result <<
"<TemplateParameters>";
970 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
971 visit(Parts.TParams[i]);
972 Result <<
"</TemplateParameters>";
975 if (Parts.Params.size() != 0) {
976 Result <<
"<Parameters>";
977 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
978 visit(Parts.Params[i]);
979 Result <<
"</Parameters>";
982 if (Parts.Exceptions.size() != 0) {
983 Result <<
"<Exceptions>";
984 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
985 visit(Parts.Exceptions[i]);
986 Result <<
"</Exceptions>";
989 if (Parts.Returns.size() != 0) {
990 Result <<
"<ResultDiscussion>";
991 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
992 visit(Parts.Returns[i]);
993 Result <<
"</ResultDiscussion>";
998 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
999 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
1001 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
1002 if (DA->getMessage().empty())
1003 Result <<
"<Deprecated/>";
1005 Result <<
"<Deprecated>";
1006 appendToResultWithXMLEscaping(DA->getMessage());
1007 Result <<
"</Deprecated>";
1010 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1011 if (UA->getMessage().empty())
1012 Result <<
"<Unavailable/>";
1014 Result <<
"<Unavailable>";
1015 appendToResultWithXMLEscaping(UA->getMessage());
1016 Result <<
"</Unavailable>";
1023 Result <<
"<Availability";
1024 StringRef Distribution;
1025 if (AA->getPlatform()) {
1026 Distribution = AvailabilityAttr::getPrettyPlatformName(
1027 AA->getPlatform()->getName());
1028 if (Distribution.empty())
1029 Distribution = AA->getPlatform()->getName();
1031 Result <<
" distribution=\"" << Distribution <<
"\">";
1032 VersionTuple IntroducedInVersion = AA->getIntroduced();
1033 if (!IntroducedInVersion.
empty()) {
1034 Result <<
"<IntroducedInVersion>"
1036 <<
"</IntroducedInVersion>";
1038 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1039 if (!DeprecatedInVersion.
empty()) {
1040 Result <<
"<DeprecatedInVersion>"
1042 <<
"</DeprecatedInVersion>";
1045 if (!RemovedAfterVersion.
empty()) {
1046 Result <<
"<RemovedAfterVersion>"
1048 <<
"</RemovedAfterVersion>";
1050 StringRef DeprecationSummary = AA->getMessage();
1051 if (!DeprecationSummary.empty()) {
1052 Result <<
"<DeprecationSummary>";
1053 appendToResultWithXMLEscaping(DeprecationSummary);
1054 Result <<
"</DeprecationSummary>";
1056 if (AA->getUnavailable())
1057 Result <<
"<Unavailable/>";
1058 Result <<
"</Availability>";
1063 bool StartTagEmitted =
false;
1064 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1065 const Comment *C = Parts.MiscBlocks[i];
1066 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1068 if (!StartTagEmitted) {
1069 Result <<
"<Discussion>";
1070 StartTagEmitted =
true;
1074 if (StartTagEmitted)
1075 Result <<
"</Discussion>";
1078 Result << RootEndTag;
1081 void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1107 void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1111 Result <<
"<![CDATA[";
1112 while (!S.empty()) {
1113 size_t Pos = S.find(
"]]>");
1115 Result <<
"]]]]><![CDATA[>";
1116 S = S.drop_front(3);
1119 if (Pos == StringRef::npos)
1122 Result << S.substr(0, Pos);
1124 S = S.drop_front(Pos);
1129 CommentToXMLConverter::CommentToXMLConverter() : FormatInMemoryUniqueId(0) {}
1135 CommentASTToHTMLConverter Converter(FC, HTML,
1137 Converter.visit(FC);
1143 CommentASTToHTMLConverter Converter(
nullptr, Text,
1145 Converter.visit(HTC);
1151 if (!FormatContext || (FormatInMemoryUniqueId % 1000) == 0) {
1159 FormatInMemoryUniqueId++);
1160 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.
comments::CommandTraits & getCommentCommandTraits() const
class LLVM_ALIGNAS(8) DependentTemplateSpecializationType const IdentifierInfo * Name
Represents a template specialization type whose template cannot be resolved, e.g. ...
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
detail::InMemoryDirectory::const_iterator I
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
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.
const TemplateArgument * iterator
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)...
DeclarationName - The name of a declaration.
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
detail::InMemoryDirectory::const_iterator E
SourceManager & getSourceManager()
bool generateUSRForDecl(const Decl *D, SmallVectorImpl< char > &Buf)
Generate a USR for a Decl, including the USR prefix.
NamedDecl - This represents a decl with a name.
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.