diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index d95f010a6fb2..93a522457e7a 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -3563,8 +3563,12 @@ CINDEX_LINKAGE CXString clang_HTMLTagComment_getAsString(CXComment Comment); * \li "para-returns" for \\returns paragraph and equivalent commands; * \li "word-returns" for the "Returns" word in \\returns paragraph. * - * Argument list is rendered as \ list with arguments sorted in function - * prototype order. + * Function argument documentation is rendered as a \ list with arguments + * sorted in function prototype order. CSS classes used: + * \li "param-name-index-NUMBER" for parameter name (\); + * \li "param-descr-index-NUMBER" for parameter description (\); + * \li "param-name-index-invalid" and "param-descr-index-invalid" are used if + * parameter index is invalid. * * \param Comment a \c CXComment_FullComment AST node. * diff --git a/clang/test/Index/annotate-comments.cpp b/clang/test/Index/annotate-comments.cpp index 9ed1c30c490e..872a9fa4242d 100644 --- a/clang/test/Index/annotate-comments.cpp +++ b/clang/test/Index/annotate-comments.cpp @@ -483,7 +483,7 @@ void comment_to_html_conversion_22(); // CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns] // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Ccc.]))))] -// CHECK: annotate-comments.cpp:271:6: FunctionDecl=comment_to_html_conversion_11:{{.*}} FullCommentAsHTML=[
x1
Aaa.
] +// CHECK: annotate-comments.cpp:271:6: FunctionDecl=comment_to_html_conversion_11:{{.*}} FullCommentAsHTML=[
x1
Aaa.
] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace @@ -491,7 +491,7 @@ void comment_to_html_conversion_22(); // CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))] -// CHECK: annotate-comments.cpp:274:6: FunctionDecl=comment_to_html_conversion_12:{{.*}} FullCommentAsHTML=[
zzz
Aaa.
] +// CHECK: annotate-comments.cpp:274:6: FunctionDecl=comment_to_html_conversion_12:{{.*}} FullCommentAsHTML=[
zzz
Aaa.
] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace @@ -499,7 +499,7 @@ void comment_to_html_conversion_22(); // CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[zzz] ParamIndex=Invalid // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))] -// CHECK: annotate-comments.cpp:278:6: FunctionDecl=comment_to_html_conversion_13:{{.*}} FullCommentAsHTML=[
x1
Aaa.
x2
Bbb.
] +// CHECK: annotate-comments.cpp:278:6: FunctionDecl=comment_to_html_conversion_13:{{.*}} FullCommentAsHTML=[
x1
Aaa.
x2
Bbb.
] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace @@ -511,7 +511,7 @@ void comment_to_html_conversion_22(); // CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))] -// CHECK: annotate-comments.cpp:283:6: FunctionDecl=comment_to_html_conversion_14:{{.*}} FullCommentAsHTML=[
x1
Aaa.
x2
Bbb.
zzz
Aaa.
] +// CHECK: annotate-comments.cpp:283:6: FunctionDecl=comment_to_html_conversion_14:{{.*}} FullCommentAsHTML=[
x1
Aaa.
x2
Bbb.
zzz
Aaa.
] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace @@ -527,7 +527,7 @@ void comment_to_html_conversion_22(); // CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))] -// CHECK: annotate-comments.cpp:292:6: FunctionDecl=comment_to_html_conversion_15:{{.*}} FullCommentAsHTML=[

Aaa.

Bbb.

x1
Ccc.
x2
Ddd.

Returns Eee.

] +// CHECK: annotate-comments.cpp:292:6: FunctionDecl=comment_to_html_conversion_15:{{.*}} FullCommentAsHTML=[

Aaa.

Bbb.

x1
Ccc.
x2
Ddd.

Returns Eee.

] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace @@ -550,7 +550,7 @@ void comment_to_html_conversion_22(); // CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns] // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Eee.]))))] -// CHECK: annotate-comments.cpp:295:6: FunctionDecl=comment_to_html_conversion_16:{{.*}} FullCommentAsHTML=[


Aaa

] +// CHECK: annotate-comments.cpp:295:6: FunctionDecl=comment_to_html_conversion_16:{{.*}} FullCommentAsHTML=[


Aaa

] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph diff --git a/clang/tools/libclang/CXComment.cpp b/clang/tools/libclang/CXComment.cpp index 8d01a4192f13..b0ed9bcc00ea 100644 --- a/clang/tools/libclang/CXComment.cpp +++ b/clang/tools/libclang/CXComment.cpp @@ -18,6 +18,7 @@ #include "clang/AST/CommentVisitor.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::cxstring; @@ -304,7 +305,8 @@ public: class CommentASTToHTMLConverter : public ConstCommentVisitor { public: - CommentASTToHTMLConverter() { } + /// \param Str accumulator for HTML. + CommentASTToHTMLConverter(SmallVectorImpl &Str) : Result(Str) { } // Inline content. void visitTextComment(const TextComment *C); @@ -330,13 +332,9 @@ public: void appendToResultWithHTMLEscaping(StringRef S); - StringRef getAsHTML() const { - return Result; - } - private: - /// Accumulator for converted HTML. - std::string Result; + /// Output stream for HTML. + llvm::raw_svector_ostream Result; }; } // end unnamed namespace @@ -355,64 +353,50 @@ void CommentASTToHTMLConverter::visitInlineCommandComment( if (CommandName == "b") { if (!HasArg0) return; - Result += ""; - Result += Arg0; - Result += ""; + Result << "" << Arg0 << ""; return; } if (CommandName == "c" || CommandName == "p") { if (!HasArg0) return; - Result += ""; - Result += Arg0; - Result += ""; + Result << "" << Arg0 << ""; return; } if (CommandName == "a" || CommandName == "e" || CommandName == "em") { if (!HasArg0) return; - Result += ""; - Result += Arg0; - Result += ""; + Result << "" << Arg0 << ""; return; } // We don't recognize this command, so just print its arguments. - for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) { - Result += C->getArgText(i); - Result += " "; - } + for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) + Result << C->getArgText(i) << " "; } void CommentASTToHTMLConverter::visitHTMLStartTagComment( const HTMLStartTagComment *C) { - Result += "<"; - Result += C->getTagName(); + Result << "<" << C->getTagName(); if (C->getNumAttrs() != 0) { for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) { - Result += " "; + Result << " "; const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); - Result += Attr.Name; - if (!Attr.Value.empty()) { - Result += "=\""; - Result += Attr.Value; - Result += " \""; - } + Result << Attr.Name; + if (!Attr.Value.empty()) + Result << "=\"" << Attr.Value << "\""; } } if (!C->isSelfClosing()) - Result += ">"; + Result << ">"; else - Result += "/>"; + Result << "/>"; } void CommentASTToHTMLConverter::visitHTMLEndTagComment( const HTMLEndTagComment *C) { - Result += "getTagName(); - Result += ">"; + Result << "getTagName() << ">"; } void CommentASTToHTMLConverter::visitParagraphComment( @@ -420,28 +404,28 @@ void CommentASTToHTMLConverter::visitParagraphComment( if (C->isWhitespace()) return; - Result += "

"; + Result << "

"; for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); I != E; ++I) { visit(*I); } - Result += "

"; + Result << "

"; } void CommentASTToHTMLConverter::visitBlockCommandComment( const BlockCommandComment *C) { StringRef CommandName = C->getCommandName(); if (CommandName == "brief" || CommandName == "short") { - Result += "

"; + Result << "

"; visitNonStandaloneParagraphComment(C->getParagraph()); - Result += "

"; + Result << "

"; return; } if (CommandName == "returns" || CommandName == "return") { - Result += "

"; - Result += "Returns "; + Result << "

" + "Returns "; visitNonStandaloneParagraphComment(C->getParagraph()); - Result += "

"; + Result << "

"; return; } // We don't know anything about this command. Just render the paragraph. @@ -450,12 +434,24 @@ void CommentASTToHTMLConverter::visitBlockCommandComment( void CommentASTToHTMLConverter::visitParamCommandComment( const ParamCommandComment *C) { - Result += "
"; - Result += C->getParamName(); - Result += "
"; - Result += "
"; + if (C->isParamIndexValid()) { + Result << "
getParamIndex() + << "\">"; + } else + Result << "
"; + + Result << C->getParamName() << "
"; + + if (C->isParamIndexValid()) { + Result << "
getParamIndex() + << "\">"; + } else + Result << "
"; + visitNonStandaloneParagraphComment(C->getParagraph()); - Result += "
"; + Result << ""; } void CommentASTToHTMLConverter::visitVerbatimBlockComment( @@ -464,13 +460,13 @@ void CommentASTToHTMLConverter::visitVerbatimBlockComment( if (NumLines == 0) return; - Result += "
";
+  Result << "
";
   for (unsigned i = 0; i != NumLines; ++i) {
     appendToResultWithHTMLEscaping(C->getText(i));
     if (i + 1 != NumLines)
-      Result.append("\n");
+      Result << '\n';
   }
-  Result += "
"; + Result << "
"; } void CommentASTToHTMLConverter::visitVerbatimBlockLineComment( @@ -480,9 +476,9 @@ void CommentASTToHTMLConverter::visitVerbatimBlockLineComment( void CommentASTToHTMLConverter::visitVerbatimLineComment( const VerbatimLineComment *C) { - Result += "
";
+  Result << "
";
   appendToResultWithHTMLEscaping(C->getText());
-  Result += "
"; + Result << "
"; } void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) { @@ -566,9 +562,9 @@ void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) { if (Brief) visit(Brief); else if (FirstParagraph) { - Result += "

"; + Result << "

"; visitNonStandaloneParagraphComment(FirstParagraph); - Result += "

"; + Result << "

"; FirstParagraphIsBrief = true; } @@ -580,14 +576,16 @@ void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) { } if (Params.size() != 0) { - Result += "
"; + Result << "
"; for (unsigned i = 0, e = Params.size(); i != e; ++i) visit(Params[i]); - Result += "
"; + Result << "
"; } if (Returns) visit(Returns); + + Result.flush(); } void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment( @@ -602,30 +600,29 @@ void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment( } void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) { - Result.reserve(Result.size() + S.size()); for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) { const char C = *I; switch (C) { case '&': - Result.append("&"); + Result << "&"; break; case '<': - Result.append("<"); + Result << "<"; break; case '>': - Result.append(">"); + Result << ">"; break; case '"': - Result.append("""); + Result << """; break; case '\'': - Result.append("'"); + Result << "'"; break; case '/': - Result.append("/"); + Result << "/"; break; default: - Result.push_back(C); + Result << C; break; } } @@ -638,9 +635,10 @@ CXString clang_HTMLTagComment_getAsString(CXComment CXC) { if (!HTC) return createCXString((const char *) 0); - CommentASTToHTMLConverter Converter; + SmallString<128> HTML; + CommentASTToHTMLConverter Converter(HTML); Converter.visit(HTC); - return createCXString(Converter.getAsHTML()); + return createCXString(HTML.str(), /* DupString = */ true); } CXString clang_FullComment_getAsHTML(CXComment CXC) { @@ -648,9 +646,10 @@ CXString clang_FullComment_getAsHTML(CXComment CXC) { if (!FC) return createCXString((const char *) 0); - CommentASTToHTMLConverter Converter; + SmallString<1024> HTML; + CommentASTToHTMLConverter Converter(HTML); Converter.visit(FC); - return createCXString(Converter.getAsHTML()); + return createCXString(HTML.str(), /* DupString = */ true); } } // end extern "C"