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]);
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(
597 std::string StringDecl = Declaration.str();
602 filename +=
"xmldecl";
603 filename += llvm::utostr(FormatInMemoryUniqueId);
605 FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
606 SourceLocation Start = FormatRewriterContext.Sources.getLocForStartOfFile(ID)
608 unsigned Length = Declaration.size();
614 Declaration = FormatRewriterContext.getRewrittenText(ID);
619 void CommentASTToXMLConverter::visitTextComment(
const TextComment *C) {
620 appendToResultWithXMLEscaping(C->
getText());
623 void CommentASTToXMLConverter::visitInlineCommandComment(
636 for (
unsigned i = 0, e = C->
getNumArgs(); i != e; ++i) {
637 appendToResultWithXMLEscaping(C->
getArgText(i));
644 appendToResultWithXMLEscaping(Arg0);
649 Result <<
"<monospaced>";
650 appendToResultWithXMLEscaping(Arg0);
651 Result <<
"</monospaced>";
655 Result <<
"<emphasized>";
656 appendToResultWithXMLEscaping(Arg0);
657 Result <<
"</emphasized>";
662 void CommentASTToXMLConverter::visitHTMLStartTagComment(
664 Result <<
"<rawHTML";
666 Result <<
" isMalformed=\"1\"";
671 llvm::raw_svector_ostream TagOS(Tag);
672 printHTMLStartTagComment(C, TagOS);
674 appendToResultWithCDATAEscaping(Tag);
676 Result <<
"</rawHTML>";
681 Result <<
"<rawHTML";
683 Result <<
" isMalformed=\"1\"";
684 Result <<
"></" << C->
getTagName() <<
"></rawHTML>";
688 CommentASTToXMLConverter::visitParagraphComment(
const ParagraphComment *C) {
689 appendParagraphCommentWithKind(C, StringRef());
692 void CommentASTToXMLConverter::appendParagraphCommentWithKind(
694 StringRef ParagraphKind) {
698 if (ParagraphKind.empty())
701 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
710 void CommentASTToXMLConverter::visitBlockCommandComment(
712 StringRef ParagraphKind;
715 case CommandTraits::KCI_attention:
716 case CommandTraits::KCI_author:
717 case CommandTraits::KCI_authors:
718 case CommandTraits::KCI_bug:
719 case CommandTraits::KCI_copyright:
720 case CommandTraits::KCI_date:
721 case CommandTraits::KCI_invariant:
722 case CommandTraits::KCI_note:
723 case CommandTraits::KCI_post:
724 case CommandTraits::KCI_pre:
725 case CommandTraits::KCI_remark:
726 case CommandTraits::KCI_remarks:
727 case CommandTraits::KCI_sa:
728 case CommandTraits::KCI_see:
729 case CommandTraits::KCI_since:
730 case CommandTraits::KCI_todo:
731 case CommandTraits::KCI_version:
732 case CommandTraits::KCI_warning:
738 appendParagraphCommentWithKind(C->
getParagraph(), ParagraphKind);
741 void CommentASTToXMLConverter::visitParamCommandComment(
743 Result <<
"<Parameter><Name>";
751 Result <<
"<IsVarArg />";
768 Result <<
"</Direction><Discussion>";
770 Result <<
"</Discussion></Parameter>";
773 void CommentASTToXMLConverter::visitTParamCommandComment(
775 Result <<
"<Parameter><Name>";
781 Result <<
"<Index>" << C->
getIndex(0) <<
"</Index>";
784 Result <<
"<Discussion>";
786 Result <<
"</Discussion></Parameter>";
789 void CommentASTToXMLConverter::visitVerbatimBlockComment(
796 case CommandTraits::KCI_code:
797 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
800 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
803 for (
unsigned i = 0; i != NumLines; ++i) {
804 appendToResultWithXMLEscaping(C->
getText(i));
805 if (i + 1 != NumLines)
808 Result <<
"</Verbatim>";
811 void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
813 llvm_unreachable(
"should not see this AST node");
816 void CommentASTToXMLConverter::visitVerbatimLineComment(
818 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
819 appendToResultWithXMLEscaping(C->
getText());
820 Result <<
"</Verbatim>";
823 void CommentASTToXMLConverter::visitFullComment(
const FullComment *C) {
824 FullCommentParts Parts(C, Traits);
827 StringRef RootEndTag;
831 RootEndTag =
"</Other>";
835 RootEndTag =
"</Function>";
836 Result <<
"<Function";
841 Result <<
" templateKind=\"template\"";
844 Result <<
" templateKind=\"specialization\"";
847 llvm_unreachable(
"partial specializations of functions "
848 "are not allowed in C++");
851 Result <<
" isInstanceMethod=\"1\"";
853 Result <<
" isClassMethod=\"1\"";
856 RootEndTag =
"</Class>";
862 Result <<
" templateKind=\"template\"";
865 Result <<
" templateKind=\"specialization\"";
868 Result <<
" templateKind=\"partialSpecialization\"";
873 RootEndTag =
"</Variable>";
874 Result <<
"<Variable";
877 RootEndTag =
"</Namespace>";
878 Result <<
"<Namespace";
881 RootEndTag =
"</Typedef>";
882 Result <<
"<Typedef";
885 RootEndTag =
"</Enum>";
894 FileID FID = LocInfo.first;
895 unsigned FileOffset = LocInfo.second;
899 Result <<
" file=\"";
900 appendToResultWithXMLEscaping(FE->getName());
912 bool FoundName =
false;
916 std::string
Name = DeclName.getAsString();
917 appendToResultWithXMLEscaping(Name);
923 Result <<
"<Name><anonymous></Name>";
931 appendToResultWithXMLEscaping(USR);
937 RootEndTag =
"</Other>";
938 Result <<
"<Other><Name>unknown</Name>";
941 if (Parts.Headerfile) {
942 Result <<
"<Headerfile>";
943 visit(Parts.Headerfile);
944 Result <<
"</Headerfile>";
949 Result <<
"<Declaration>";
951 getSourceTextOfDeclaration(DI, Declaration);
952 formatTextOfDeclaration(DI, Declaration);
953 appendToResultWithXMLEscaping(Declaration);
954 Result <<
"</Declaration>";
957 bool FirstParagraphIsBrief =
false;
959 Result <<
"<Abstract>";
961 Result <<
"</Abstract>";
962 }
else if (Parts.FirstParagraph) {
963 Result <<
"<Abstract>";
964 visit(Parts.FirstParagraph);
965 Result <<
"</Abstract>";
966 FirstParagraphIsBrief =
true;
969 if (Parts.TParams.size() != 0) {
970 Result <<
"<TemplateParameters>";
971 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
972 visit(Parts.TParams[i]);
973 Result <<
"</TemplateParameters>";
976 if (Parts.Params.size() != 0) {
977 Result <<
"<Parameters>";
978 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
979 visit(Parts.Params[i]);
980 Result <<
"</Parameters>";
983 if (Parts.Exceptions.size() != 0) {
984 Result <<
"<Exceptions>";
985 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
986 visit(Parts.Exceptions[i]);
987 Result <<
"</Exceptions>";
990 if (Parts.Returns.size() != 0) {
991 Result <<
"<ResultDiscussion>";
992 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
993 visit(Parts.Returns[i]);
994 Result <<
"</ResultDiscussion>";
999 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
1000 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
1002 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
1003 if (DA->getMessage().empty())
1004 Result <<
"<Deprecated/>";
1006 Result <<
"<Deprecated>";
1007 appendToResultWithXMLEscaping(DA->getMessage());
1008 Result <<
"</Deprecated>";
1011 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1012 if (UA->getMessage().empty())
1013 Result <<
"<Unavailable/>";
1015 Result <<
"<Unavailable>";
1016 appendToResultWithXMLEscaping(UA->getMessage());
1017 Result <<
"</Unavailable>";
1024 Result <<
"<Availability";
1025 StringRef Distribution;
1026 if (AA->getPlatform()) {
1027 Distribution = AvailabilityAttr::getPrettyPlatformName(
1028 AA->getPlatform()->getName());
1029 if (Distribution.empty())
1030 Distribution = AA->getPlatform()->getName();
1032 Result <<
" distribution=\"" << Distribution <<
"\">";
1033 VersionTuple IntroducedInVersion = AA->getIntroduced();
1034 if (!IntroducedInVersion.
empty()) {
1035 Result <<
"<IntroducedInVersion>"
1037 <<
"</IntroducedInVersion>";
1039 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1040 if (!DeprecatedInVersion.
empty()) {
1041 Result <<
"<DeprecatedInVersion>"
1043 <<
"</DeprecatedInVersion>";
1046 if (!RemovedAfterVersion.
empty()) {
1047 Result <<
"<RemovedAfterVersion>"
1049 <<
"</RemovedAfterVersion>";
1051 StringRef DeprecationSummary = AA->getMessage();
1052 if (!DeprecationSummary.empty()) {
1053 Result <<
"<DeprecationSummary>";
1054 appendToResultWithXMLEscaping(DeprecationSummary);
1055 Result <<
"</DeprecationSummary>";
1057 if (AA->getUnavailable())
1058 Result <<
"<Unavailable/>";
1059 Result <<
"</Availability>";
1064 bool StartTagEmitted =
false;
1065 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1066 const Comment *C = Parts.MiscBlocks[i];
1067 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1069 if (!StartTagEmitted) {
1070 Result <<
"<Discussion>";
1071 StartTagEmitted =
true;
1075 if (StartTagEmitted)
1076 Result <<
"</Discussion>";
1079 Result << RootEndTag;
1082 void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1108 void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1112 Result <<
"<![CDATA[";
1113 while (!S.empty()) {
1114 size_t Pos = S.find(
"]]>");
1116 Result <<
"]]]]><![CDATA[>";
1117 S = S.drop_front(3);
1120 if (Pos == StringRef::npos)
1123 Result << S.substr(0, Pos);
1125 S = S.drop_front(Pos);
1130 CommentToXMLConverter::CommentToXMLConverter() : FormatInMemoryUniqueId(0) {}
1136 CommentASTToHTMLConverter Converter(FC, HTML,
1138 Converter.visit(FC);
1144 CommentASTToHTMLConverter Converter(
nullptr, Text,
1146 Converter.visit(HTC);
1152 if (!FormatContext || (FormatInMemoryUniqueId % 1000) == 0) {
1160 FormatInMemoryUniqueId++);
1161 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.
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.
const TemplateArgument * iterator
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)...
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
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
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.