17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/TinyPtrVector.h"
19 #include "llvm/Support/raw_ostream.h"
21 using namespace clang;
22 using namespace clang::comments;
23 using namespace clang::index;
29 class ParamCommandCommentCompareIndex {
48 return LHSIndex < RHSIndex;
56 class TParamCommandCommentComparePosition {
81 struct FullCommentParts {
92 llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
96 FullCommentParts::FullCommentParts(
const FullComment *C,
98 Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
105 case Comment::NoCommentKind:
108 case Comment::ParagraphCommentKind: {
115 MiscBlocks.push_back(PC);
119 case Comment::BlockCommandCommentKind: {
122 if (!Brief && Info->IsBriefCommand) {
126 if (!Headerfile && Info->IsHeaderfileCommand) {
130 if (Info->IsReturnsCommand) {
131 Returns.push_back(BCC);
134 if (Info->IsThrowsCommand) {
135 Exceptions.push_back(BCC);
138 MiscBlocks.push_back(BCC);
142 case Comment::ParamCommandCommentKind: {
150 Params.push_back(PCC);
154 case Comment::TParamCommandCommentKind: {
162 TParams.push_back(TPCC);
166 case Comment::VerbatimBlockCommentKind:
167 MiscBlocks.push_back(cast<BlockCommandComment>(Child));
170 case Comment::VerbatimLineCommentKind: {
173 if (!Info->IsDeclarationCommand)
174 MiscBlocks.push_back(VLC);
178 case Comment::TextCommentKind:
179 case Comment::InlineCommandCommentKind:
180 case Comment::HTMLStartTagCommentKind:
181 case Comment::HTMLEndTagCommentKind:
182 case Comment::VerbatimBlockLineCommentKind:
183 case Comment::FullCommentKind:
184 llvm_unreachable(
"AST node of this kind can't be a child of "
192 std::stable_sort(Params.begin(), Params.end(),
193 ParamCommandCommentCompareIndex());
195 std::stable_sort(TParams.begin(), TParams.end(),
196 TParamCommandCommentComparePosition());
200 llvm::raw_svector_ostream &Result) {
204 for (
unsigned i = 0, e = C->
getNumAttrs(); i != e; i++) {
208 if (!Attr.
Value.empty())
209 Result <<
"=\"" << Attr.
Value <<
"\"";
219 class CommentASTToHTMLConverter :
226 FC(FC), Result(Str), Traits(Traits)
252 void appendToResultWithHTMLEscaping(StringRef
S);
257 llvm::raw_svector_ostream Result;
263 void CommentASTToHTMLConverter::visitTextComment(
const TextComment *C) {
264 appendToResultWithHTMLEscaping(C->
getText());
267 void CommentASTToHTMLConverter::visitInlineCommandComment(
279 case InlineCommandComment::RenderNormal:
280 for (
unsigned i = 0, e = C->
getNumArgs(); i != e; ++i) {
281 appendToResultWithHTMLEscaping(C->
getArgText(i));
286 case InlineCommandComment::RenderBold:
289 appendToResultWithHTMLEscaping(Arg0);
292 case InlineCommandComment::RenderMonospaced:
295 appendToResultWithHTMLEscaping(Arg0);
298 case InlineCommandComment::RenderEmphasized:
301 appendToResultWithHTMLEscaping(Arg0);
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;
586 void CommentASTToXMLConverter::formatTextOfDeclaration(
589 StringRef StringDecl(Declaration.c_str(), Declaration.size());
593 unsigned Length = Declaration.size();
600 if (static_cast<bool>(FormattedStringDecl)) {
601 Declaration = *FormattedStringDecl;
607 void CommentASTToXMLConverter::visitTextComment(
const TextComment *C) {
608 appendToResultWithXMLEscaping(C->
getText());
611 void CommentASTToXMLConverter::visitInlineCommandComment(
623 case InlineCommandComment::RenderNormal:
624 for (
unsigned i = 0, e = C->
getNumArgs(); i != e; ++i) {
625 appendToResultWithXMLEscaping(C->
getArgText(i));
629 case InlineCommandComment::RenderBold:
632 appendToResultWithXMLEscaping(Arg0);
635 case InlineCommandComment::RenderMonospaced:
637 Result <<
"<monospaced>";
638 appendToResultWithXMLEscaping(Arg0);
639 Result <<
"</monospaced>";
641 case InlineCommandComment::RenderEmphasized:
643 Result <<
"<emphasized>";
644 appendToResultWithXMLEscaping(Arg0);
645 Result <<
"</emphasized>";
650 void CommentASTToXMLConverter::visitHTMLStartTagComment(
652 Result <<
"<rawHTML";
654 Result <<
" isMalformed=\"1\"";
659 llvm::raw_svector_ostream TagOS(Tag);
660 printHTMLStartTagComment(C, TagOS);
662 appendToResultWithCDATAEscaping(Tag);
664 Result <<
"</rawHTML>";
669 Result <<
"<rawHTML";
671 Result <<
" isMalformed=\"1\"";
672 Result <<
"></" << C->
getTagName() <<
"></rawHTML>";
676 CommentASTToXMLConverter::visitParagraphComment(
const ParagraphComment *C) {
677 appendParagraphCommentWithKind(C, StringRef());
680 void CommentASTToXMLConverter::appendParagraphCommentWithKind(
682 StringRef ParagraphKind) {
686 if (ParagraphKind.empty())
689 Result <<
"<Para kind=\"" << ParagraphKind <<
"\">";
698 void CommentASTToXMLConverter::visitBlockCommandComment(
700 StringRef ParagraphKind;
703 case CommandTraits::KCI_attention:
704 case CommandTraits::KCI_author:
705 case CommandTraits::KCI_authors:
706 case CommandTraits::KCI_bug:
707 case CommandTraits::KCI_copyright:
708 case CommandTraits::KCI_date:
709 case CommandTraits::KCI_invariant:
710 case CommandTraits::KCI_note:
711 case CommandTraits::KCI_post:
712 case CommandTraits::KCI_pre:
713 case CommandTraits::KCI_remark:
714 case CommandTraits::KCI_remarks:
715 case CommandTraits::KCI_sa:
716 case CommandTraits::KCI_see:
717 case CommandTraits::KCI_since:
718 case CommandTraits::KCI_todo:
719 case CommandTraits::KCI_version:
720 case CommandTraits::KCI_warning:
726 appendParagraphCommentWithKind(C->
getParagraph(), ParagraphKind);
729 void CommentASTToXMLConverter::visitParamCommandComment(
731 Result <<
"<Parameter><Name>";
739 Result <<
"<IsVarArg />";
746 case ParamCommandComment::In:
749 case ParamCommandComment::Out:
752 case ParamCommandComment::InOut:
756 Result <<
"</Direction><Discussion>";
758 Result <<
"</Discussion></Parameter>";
761 void CommentASTToXMLConverter::visitTParamCommandComment(
763 Result <<
"<Parameter><Name>";
769 Result <<
"<Index>" << C->
getIndex(0) <<
"</Index>";
772 Result <<
"<Discussion>";
774 Result <<
"</Discussion></Parameter>";
777 void CommentASTToXMLConverter::visitVerbatimBlockComment(
784 case CommandTraits::KCI_code:
785 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"code\">";
788 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
791 for (
unsigned i = 0; i != NumLines; ++i) {
792 appendToResultWithXMLEscaping(C->
getText(i));
793 if (i + 1 != NumLines)
796 Result <<
"</Verbatim>";
799 void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
801 llvm_unreachable(
"should not see this AST node");
804 void CommentASTToXMLConverter::visitVerbatimLineComment(
806 Result <<
"<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
807 appendToResultWithXMLEscaping(C->
getText());
808 Result <<
"</Verbatim>";
811 void CommentASTToXMLConverter::visitFullComment(
const FullComment *C) {
812 FullCommentParts Parts(C, Traits);
815 StringRef RootEndTag;
818 case DeclInfo::OtherKind:
819 RootEndTag =
"</Other>";
822 case DeclInfo::FunctionKind:
823 RootEndTag =
"</Function>";
824 Result <<
"<Function";
826 case DeclInfo::NotTemplate:
828 case DeclInfo::Template:
829 Result <<
" templateKind=\"template\"";
832 Result <<
" templateKind=\"specialization\"";
835 llvm_unreachable(
"partial specializations of functions "
836 "are not allowed in C++");
839 Result <<
" isInstanceMethod=\"1\"";
841 Result <<
" isClassMethod=\"1\"";
843 case DeclInfo::ClassKind:
844 RootEndTag =
"</Class>";
847 case DeclInfo::NotTemplate:
849 case DeclInfo::Template:
850 Result <<
" templateKind=\"template\"";
853 Result <<
" templateKind=\"specialization\"";
856 Result <<
" templateKind=\"partialSpecialization\"";
860 case DeclInfo::VariableKind:
861 RootEndTag =
"</Variable>";
862 Result <<
"<Variable";
864 case DeclInfo::NamespaceKind:
865 RootEndTag =
"</Namespace>";
866 Result <<
"<Namespace";
868 case DeclInfo::TypedefKind:
869 RootEndTag =
"</Typedef>";
870 Result <<
"<Typedef";
872 case DeclInfo::EnumKind:
873 RootEndTag =
"</Enum>";
882 FileID FID = LocInfo.first;
883 unsigned FileOffset = LocInfo.second;
887 Result <<
" file=\"";
888 appendToResultWithXMLEscaping(FE->getName());
900 bool FoundName =
false;
904 std::string
Name = DeclName.getAsString();
905 appendToResultWithXMLEscaping(Name);
911 Result <<
"<Name><anonymous></Name>";
919 appendToResultWithXMLEscaping(USR);
925 RootEndTag =
"</Other>";
926 Result <<
"<Other><Name>unknown</Name>";
929 if (Parts.Headerfile) {
930 Result <<
"<Headerfile>";
931 visit(Parts.Headerfile);
932 Result <<
"</Headerfile>";
937 Result <<
"<Declaration>";
939 getSourceTextOfDeclaration(DI, Declaration);
940 formatTextOfDeclaration(DI, Declaration);
941 appendToResultWithXMLEscaping(Declaration);
942 Result <<
"</Declaration>";
945 bool FirstParagraphIsBrief =
false;
947 Result <<
"<Abstract>";
949 Result <<
"</Abstract>";
950 }
else if (Parts.FirstParagraph) {
951 Result <<
"<Abstract>";
952 visit(Parts.FirstParagraph);
953 Result <<
"</Abstract>";
954 FirstParagraphIsBrief =
true;
957 if (Parts.TParams.size() != 0) {
958 Result <<
"<TemplateParameters>";
959 for (
unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
960 visit(Parts.TParams[i]);
961 Result <<
"</TemplateParameters>";
964 if (Parts.Params.size() != 0) {
965 Result <<
"<Parameters>";
966 for (
unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
967 visit(Parts.Params[i]);
968 Result <<
"</Parameters>";
971 if (Parts.Exceptions.size() != 0) {
972 Result <<
"<Exceptions>";
973 for (
unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
974 visit(Parts.Exceptions[i]);
975 Result <<
"</Exceptions>";
978 if (Parts.Returns.size() != 0) {
979 Result <<
"<ResultDiscussion>";
980 for (
unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
981 visit(Parts.Returns[i]);
982 Result <<
"</ResultDiscussion>";
987 for (
unsigned i = 0, e = Attrs.size(); i != e; i++) {
988 const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
990 if (
const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
991 if (DA->getMessage().empty())
992 Result <<
"<Deprecated/>";
994 Result <<
"<Deprecated>";
995 appendToResultWithXMLEscaping(DA->getMessage());
996 Result <<
"</Deprecated>";
999 else if (
const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
1000 if (UA->getMessage().empty())
1001 Result <<
"<Unavailable/>";
1003 Result <<
"<Unavailable>";
1004 appendToResultWithXMLEscaping(UA->getMessage());
1005 Result <<
"</Unavailable>";
1012 Result <<
"<Availability";
1013 StringRef Distribution;
1014 if (AA->getPlatform()) {
1015 Distribution = AvailabilityAttr::getPrettyPlatformName(
1016 AA->getPlatform()->getName());
1017 if (Distribution.empty())
1018 Distribution = AA->getPlatform()->getName();
1020 Result <<
" distribution=\"" << Distribution <<
"\">";
1021 VersionTuple IntroducedInVersion = AA->getIntroduced();
1022 if (!IntroducedInVersion.
empty()) {
1023 Result <<
"<IntroducedInVersion>"
1025 <<
"</IntroducedInVersion>";
1027 VersionTuple DeprecatedInVersion = AA->getDeprecated();
1028 if (!DeprecatedInVersion.
empty()) {
1029 Result <<
"<DeprecatedInVersion>"
1031 <<
"</DeprecatedInVersion>";
1034 if (!RemovedAfterVersion.
empty()) {
1035 Result <<
"<RemovedAfterVersion>"
1037 <<
"</RemovedAfterVersion>";
1039 StringRef DeprecationSummary = AA->getMessage();
1040 if (!DeprecationSummary.empty()) {
1041 Result <<
"<DeprecationSummary>";
1042 appendToResultWithXMLEscaping(DeprecationSummary);
1043 Result <<
"</DeprecationSummary>";
1045 if (AA->getUnavailable())
1046 Result <<
"<Unavailable/>";
1047 Result <<
"</Availability>";
1052 bool StartTagEmitted =
false;
1053 for (
unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
1054 const Comment *C = Parts.MiscBlocks[i];
1055 if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
1057 if (!StartTagEmitted) {
1058 Result <<
"<Discussion>";
1059 StartTagEmitted =
true;
1063 if (StartTagEmitted)
1064 Result <<
"</Discussion>";
1067 Result << RootEndTag;
1070 void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
1071 for (StringRef::iterator
I = S.begin(),
E = S.end();
I !=
E; ++
I) {
1096 void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
1100 Result <<
"<![CDATA[";
1101 while (!S.empty()) {
1102 size_t Pos = S.find(
"]]>");
1104 Result <<
"]]]]><![CDATA[>";
1105 S = S.drop_front(3);
1108 if (Pos == StringRef::npos)
1111 Result << S.substr(0, Pos);
1113 S = S.drop_front(Pos);
1124 CommentASTToHTMLConverter Converter(FC, HTML,
1126 Converter.visit(FC);
1132 CommentASTToHTMLConverter Converter(
nullptr, Text,
1134 Converter.visit(HTC);
1142 Converter.visit(FC);
Defines the clang::ASTContext interface.
Represents a version number in the form major[.minor[.subminor[.build]]].
Describes how types, statements, expressions, and declarations should be printed. ...
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...
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.
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). ...
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.