2012-07-21 05:34:34 +08:00
|
|
|
//===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines all libclang APIs related to walking comment AST.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang-c/Index.h"
|
|
|
|
#include "CXString.h"
|
|
|
|
#include "CXComment.h"
|
|
|
|
|
|
|
|
#include "clang/AST/CommentVisitor.h"
|
|
|
|
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2012-07-21 09:47:43 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-07-21 05:34:34 +08:00
|
|
|
|
2012-07-31 01:49:32 +08:00
|
|
|
#include <climits>
|
|
|
|
|
2012-07-21 05:34:34 +08:00
|
|
|
using namespace clang;
|
|
|
|
using namespace clang::cxstring;
|
|
|
|
using namespace clang::comments;
|
|
|
|
using namespace clang::cxcomment;
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
|
|
|
|
const Comment *C = getASTNode(CXC);
|
|
|
|
if (!C)
|
|
|
|
return CXComment_Null;
|
|
|
|
|
|
|
|
switch (C->getCommentKind()) {
|
|
|
|
case Comment::NoCommentKind:
|
|
|
|
return CXComment_Null;
|
|
|
|
|
|
|
|
case Comment::TextCommentKind:
|
|
|
|
return CXComment_Text;
|
|
|
|
|
|
|
|
case Comment::InlineCommandCommentKind:
|
|
|
|
return CXComment_InlineCommand;
|
|
|
|
|
|
|
|
case Comment::HTMLStartTagCommentKind:
|
|
|
|
return CXComment_HTMLStartTag;
|
|
|
|
|
|
|
|
case Comment::HTMLEndTagCommentKind:
|
|
|
|
return CXComment_HTMLEndTag;
|
|
|
|
|
|
|
|
case Comment::ParagraphCommentKind:
|
|
|
|
return CXComment_Paragraph;
|
|
|
|
|
|
|
|
case Comment::BlockCommandCommentKind:
|
|
|
|
return CXComment_BlockCommand;
|
|
|
|
|
|
|
|
case Comment::ParamCommandCommentKind:
|
|
|
|
return CXComment_ParamCommand;
|
|
|
|
|
|
|
|
case Comment::VerbatimBlockCommentKind:
|
|
|
|
return CXComment_VerbatimBlockCommand;
|
|
|
|
|
|
|
|
case Comment::VerbatimBlockLineCommentKind:
|
|
|
|
return CXComment_VerbatimBlockLine;
|
|
|
|
|
|
|
|
case Comment::VerbatimLineCommentKind:
|
|
|
|
return CXComment_VerbatimLine;
|
|
|
|
|
|
|
|
case Comment::FullCommentKind:
|
|
|
|
return CXComment_FullComment;
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown CommentKind");
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned clang_Comment_getNumChildren(CXComment CXC) {
|
|
|
|
const Comment *C = getASTNode(CXC);
|
|
|
|
if (!C)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return C->child_count();
|
|
|
|
}
|
|
|
|
|
|
|
|
CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
|
|
|
|
const Comment *C = getASTNode(CXC);
|
|
|
|
if (!C || ChildIdx >= C->child_count())
|
|
|
|
return createCXComment(NULL);
|
|
|
|
|
|
|
|
return createCXComment(*(C->child_begin() + ChildIdx));
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned clang_Comment_isWhitespace(CXComment CXC) {
|
|
|
|
const Comment *C = getASTNode(CXC);
|
|
|
|
if (!C)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (const TextComment *TC = dyn_cast<TextComment>(C))
|
|
|
|
return TC->isWhitespace();
|
|
|
|
|
|
|
|
if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
|
|
|
|
return PC->isWhitespace();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
|
|
|
|
const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
|
|
|
|
if (!ICC)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return ICC->hasTrailingNewline();
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_TextComment_getText(CXComment CXC) {
|
|
|
|
const TextComment *TC = getASTNodeAs<TextComment>(CXC);
|
|
|
|
if (!TC)
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(TC->getText(), /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
|
|
|
|
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
|
|
|
|
if (!ICC)
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(ICC->getCommandName(), /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
2012-07-24 00:43:01 +08:00
|
|
|
enum CXCommentInlineCommandRenderKind
|
|
|
|
clang_InlineCommandComment_getRenderKind(CXComment CXC) {
|
|
|
|
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
|
|
|
|
if (!ICC)
|
|
|
|
return CXCommentInlineCommandRenderKind_Normal;
|
|
|
|
|
|
|
|
switch (ICC->getRenderKind()) {
|
|
|
|
case InlineCommandComment::RenderNormal:
|
|
|
|
return CXCommentInlineCommandRenderKind_Normal;
|
|
|
|
|
|
|
|
case InlineCommandComment::RenderBold:
|
|
|
|
return CXCommentInlineCommandRenderKind_Bold;
|
|
|
|
|
|
|
|
case InlineCommandComment::RenderMonospaced:
|
|
|
|
return CXCommentInlineCommandRenderKind_Monospaced;
|
|
|
|
|
|
|
|
case InlineCommandComment::RenderEmphasized:
|
|
|
|
return CXCommentInlineCommandRenderKind_Emphasized;
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown InlineCommandComment::RenderKind");
|
|
|
|
}
|
|
|
|
|
2012-07-21 05:34:34 +08:00
|
|
|
unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
|
|
|
|
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
|
|
|
|
if (!ICC)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return ICC->getNumArgs();
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_InlineCommandComment_getArgText(CXComment CXC,
|
|
|
|
unsigned ArgIdx) {
|
|
|
|
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
|
|
|
|
if (!ICC || ArgIdx >= ICC->getNumArgs())
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(ICC->getArgText(ArgIdx), /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
|
|
|
|
const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
|
|
|
|
if (!HTC)
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(HTC->getTagName(), /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
|
|
|
|
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
|
|
|
|
if (!HST)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return HST->isSelfClosing();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
|
|
|
|
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
|
|
|
|
if (!HST)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return HST->getNumAttrs();
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
|
|
|
|
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
|
|
|
|
if (!HST || AttrIdx >= HST->getNumAttrs())
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(HST->getAttr(AttrIdx).Name, /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
|
|
|
|
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
|
|
|
|
if (!HST || AttrIdx >= HST->getNumAttrs())
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(HST->getAttr(AttrIdx).Value, /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
|
|
|
|
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
|
|
|
|
if (!BCC)
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(BCC->getCommandName(), /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
|
|
|
|
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
|
|
|
|
if (!BCC)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return BCC->getNumArgs();
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_BlockCommandComment_getArgText(CXComment CXC,
|
|
|
|
unsigned ArgIdx) {
|
|
|
|
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
|
|
|
|
if (!BCC || ArgIdx >= BCC->getNumArgs())
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(BCC->getArgText(ArgIdx), /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
|
|
|
|
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
|
|
|
|
if (!BCC)
|
|
|
|
return createCXComment(NULL);
|
|
|
|
|
|
|
|
return createCXComment(BCC->getParagraph());
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
|
|
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
2012-07-24 03:41:49 +08:00
|
|
|
if (!PCC || !PCC->hasParamName())
|
2012-07-21 05:34:34 +08:00
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(PCC->getParamName(), /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
|
|
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
|
|
|
if (!PCC)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return PCC->isParamIndexValid();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
|
|
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
2012-07-31 01:38:19 +08:00
|
|
|
if (!PCC || !PCC->isParamIndexValid())
|
2012-07-21 05:34:34 +08:00
|
|
|
return ParamCommandComment::InvalidParamIndex;
|
|
|
|
|
|
|
|
return PCC->getParamIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
|
|
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
|
|
|
if (!PCC)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return PCC->isDirectionExplicit();
|
|
|
|
}
|
|
|
|
|
|
|
|
enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
|
|
|
|
CXComment CXC) {
|
|
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
|
|
|
if (!PCC)
|
|
|
|
return CXCommentParamPassDirection_In;
|
|
|
|
|
|
|
|
switch (PCC->getDirection()) {
|
|
|
|
case ParamCommandComment::In:
|
|
|
|
return CXCommentParamPassDirection_In;
|
|
|
|
|
|
|
|
case ParamCommandComment::Out:
|
|
|
|
return CXCommentParamPassDirection_Out;
|
|
|
|
|
|
|
|
case ParamCommandComment::InOut:
|
|
|
|
return CXCommentParamPassDirection_InOut;
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown ParamCommandComment::PassDirection");
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
|
|
|
|
const VerbatimBlockLineComment *VBL =
|
|
|
|
getASTNodeAs<VerbatimBlockLineComment>(CXC);
|
|
|
|
if (!VBL)
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(VBL->getText(), /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_VerbatimLineComment_getText(CXComment CXC) {
|
|
|
|
const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
|
|
|
|
if (!VLC)
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
|
|
|
return createCXString(VLC->getText(), /*DupString=*/ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end extern "C"
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Helpers for converting comment AST to HTML.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2012-07-31 03:47:34 +08:00
|
|
|
/// This comparison will sort parameters with valid index by index and
|
|
|
|
/// invalid (unresolved) parameters last.
|
2012-07-21 05:34:34 +08:00
|
|
|
class ParamCommandCommentCompareIndex {
|
|
|
|
public:
|
|
|
|
bool operator()(const ParamCommandComment *LHS,
|
|
|
|
const ParamCommandComment *RHS) const {
|
2012-07-31 01:38:19 +08:00
|
|
|
unsigned LHSIndex = UINT_MAX;
|
|
|
|
unsigned RHSIndex = UINT_MAX;
|
|
|
|
if (LHS->isParamIndexValid())
|
|
|
|
LHSIndex = LHS->getParamIndex();
|
|
|
|
if (RHS->isParamIndexValid())
|
|
|
|
RHSIndex = RHS->getParamIndex();
|
|
|
|
|
|
|
|
return LHSIndex < RHSIndex;
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class CommentASTToHTMLConverter :
|
|
|
|
public ConstCommentVisitor<CommentASTToHTMLConverter> {
|
|
|
|
public:
|
2012-07-21 09:47:43 +08:00
|
|
|
/// \param Str accumulator for HTML.
|
|
|
|
CommentASTToHTMLConverter(SmallVectorImpl<char> &Str) : Result(Str) { }
|
2012-07-21 05:34:34 +08:00
|
|
|
|
|
|
|
// Inline content.
|
|
|
|
void visitTextComment(const TextComment *C);
|
|
|
|
void visitInlineCommandComment(const InlineCommandComment *C);
|
|
|
|
void visitHTMLStartTagComment(const HTMLStartTagComment *C);
|
|
|
|
void visitHTMLEndTagComment(const HTMLEndTagComment *C);
|
|
|
|
|
|
|
|
// Block content.
|
|
|
|
void visitParagraphComment(const ParagraphComment *C);
|
|
|
|
void visitBlockCommandComment(const BlockCommandComment *C);
|
|
|
|
void visitParamCommandComment(const ParamCommandComment *C);
|
|
|
|
void visitVerbatimBlockComment(const VerbatimBlockComment *C);
|
|
|
|
void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
|
|
|
|
void visitVerbatimLineComment(const VerbatimLineComment *C);
|
|
|
|
|
|
|
|
void visitFullComment(const FullComment *C);
|
|
|
|
|
|
|
|
// Helpers.
|
|
|
|
|
|
|
|
/// Convert a paragraph that is not a block by itself (an argument to some
|
|
|
|
/// command).
|
|
|
|
void visitNonStandaloneParagraphComment(const ParagraphComment *C);
|
|
|
|
|
|
|
|
void appendToResultWithHTMLEscaping(StringRef S);
|
|
|
|
|
|
|
|
private:
|
2012-07-21 09:47:43 +08:00
|
|
|
/// Output stream for HTML.
|
|
|
|
llvm::raw_svector_ostream Result;
|
2012-07-21 05:34:34 +08:00
|
|
|
};
|
|
|
|
} // end unnamed namespace
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
|
|
|
|
appendToResultWithHTMLEscaping(C->getText());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitInlineCommandComment(
|
|
|
|
const InlineCommandComment *C) {
|
2012-07-24 00:43:01 +08:00
|
|
|
// Nothing to render if no arguments supplied.
|
|
|
|
if (C->getNumArgs() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Nothing to render if argument is empty.
|
|
|
|
StringRef Arg0 = C->getArgText(0);
|
|
|
|
if (Arg0.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (C->getRenderKind()) {
|
|
|
|
case InlineCommandComment::RenderNormal:
|
|
|
|
for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
|
|
|
|
Result << C->getArgText(i) << " ";
|
|
|
|
return;
|
|
|
|
|
|
|
|
case InlineCommandComment::RenderBold:
|
|
|
|
assert(C->getNumArgs() == 1);
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<b>" << Arg0 << "</b>";
|
2012-07-21 05:34:34 +08:00
|
|
|
return;
|
2012-07-24 00:43:01 +08:00
|
|
|
case InlineCommandComment::RenderMonospaced:
|
|
|
|
assert(C->getNumArgs() == 1);
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<tt>" << Arg0 << "</tt>";
|
2012-07-21 05:34:34 +08:00
|
|
|
return;
|
2012-07-24 00:43:01 +08:00
|
|
|
case InlineCommandComment::RenderEmphasized:
|
|
|
|
assert(C->getNumArgs() == 1);
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<em>" << Arg0 << "</em>";
|
2012-07-21 05:34:34 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitHTMLStartTagComment(
|
|
|
|
const HTMLStartTagComment *C) {
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<" << C->getTagName();
|
2012-07-21 05:34:34 +08:00
|
|
|
|
|
|
|
if (C->getNumAttrs() != 0) {
|
|
|
|
for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << " ";
|
2012-07-21 05:34:34 +08:00
|
|
|
const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << Attr.Name;
|
|
|
|
if (!Attr.Value.empty())
|
|
|
|
Result << "=\"" << Attr.Value << "\"";
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!C->isSelfClosing())
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << ">";
|
2012-07-21 05:34:34 +08:00
|
|
|
else
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "/>";
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitHTMLEndTagComment(
|
|
|
|
const HTMLEndTagComment *C) {
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "</" << C->getTagName() << ">";
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitParagraphComment(
|
|
|
|
const ParagraphComment *C) {
|
|
|
|
if (C->isWhitespace())
|
|
|
|
return;
|
|
|
|
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<p>";
|
2012-07-21 05:34:34 +08:00
|
|
|
for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
visit(*I);
|
|
|
|
}
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "</p>";
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitBlockCommandComment(
|
|
|
|
const BlockCommandComment *C) {
|
|
|
|
StringRef CommandName = C->getCommandName();
|
|
|
|
if (CommandName == "brief" || CommandName == "short") {
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<p class=\"para-brief\">";
|
2012-07-21 05:34:34 +08:00
|
|
|
visitNonStandaloneParagraphComment(C->getParagraph());
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "</p>";
|
2012-07-21 05:34:34 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-07-26 01:14:58 +08:00
|
|
|
if (CommandName == "returns" || CommandName == "return" ||
|
|
|
|
CommandName == "result") {
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<p class=\"para-returns\">"
|
|
|
|
"<span class=\"word-returns\">Returns</span> ";
|
2012-07-21 05:34:34 +08:00
|
|
|
visitNonStandaloneParagraphComment(C->getParagraph());
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "</p>";
|
2012-07-21 05:34:34 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// We don't know anything about this command. Just render the paragraph.
|
|
|
|
visit(C->getParagraph());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitParamCommandComment(
|
|
|
|
const ParamCommandComment *C) {
|
2012-07-21 09:47:43 +08:00
|
|
|
if (C->isParamIndexValid()) {
|
|
|
|
Result << "<dt class=\"param-name-index-"
|
|
|
|
<< C->getParamIndex()
|
|
|
|
<< "\">";
|
|
|
|
} else
|
|
|
|
Result << "<dt class=\"param-name-index-invalid\">";
|
|
|
|
|
|
|
|
Result << C->getParamName() << "</dt>";
|
|
|
|
|
|
|
|
if (C->isParamIndexValid()) {
|
|
|
|
Result << "<dd class=\"param-descr-index-"
|
|
|
|
<< C->getParamIndex()
|
|
|
|
<< "\">";
|
|
|
|
} else
|
|
|
|
Result << "<dd class=\"param-descr-index-invalid\">";
|
|
|
|
|
2012-07-21 05:34:34 +08:00
|
|
|
visitNonStandaloneParagraphComment(C->getParagraph());
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "</dd>";
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitVerbatimBlockComment(
|
|
|
|
const VerbatimBlockComment *C) {
|
|
|
|
unsigned NumLines = C->getNumLines();
|
|
|
|
if (NumLines == 0)
|
|
|
|
return;
|
|
|
|
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<pre>";
|
2012-07-21 05:34:34 +08:00
|
|
|
for (unsigned i = 0; i != NumLines; ++i) {
|
|
|
|
appendToResultWithHTMLEscaping(C->getText(i));
|
|
|
|
if (i + 1 != NumLines)
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << '\n';
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "</pre>";
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
|
|
|
|
const VerbatimBlockLineComment *C) {
|
|
|
|
llvm_unreachable("should not see this AST node");
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitVerbatimLineComment(
|
|
|
|
const VerbatimLineComment *C) {
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<pre>";
|
2012-07-21 05:34:34 +08:00
|
|
|
appendToResultWithHTMLEscaping(C->getText());
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "</pre>";
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
|
|
|
|
const BlockContentComment *Brief = NULL;
|
|
|
|
const ParagraphComment *FirstParagraph = NULL;
|
|
|
|
const BlockCommandComment *Returns = NULL;
|
|
|
|
SmallVector<const ParamCommandComment *, 8> Params;
|
|
|
|
SmallVector<const BlockContentComment *, 8> MiscBlocks;
|
|
|
|
|
|
|
|
// Extract various blocks into separate variables and vectors above.
|
|
|
|
for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
const Comment *Child = *I;
|
|
|
|
if (!Child)
|
|
|
|
continue;
|
|
|
|
switch (Child->getCommentKind()) {
|
|
|
|
case Comment::NoCommentKind:
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case Comment::ParagraphCommentKind: {
|
|
|
|
const ParagraphComment *PC = cast<ParagraphComment>(Child);
|
|
|
|
if (PC->isWhitespace())
|
|
|
|
break;
|
|
|
|
if (!FirstParagraph)
|
|
|
|
FirstParagraph = PC;
|
|
|
|
|
|
|
|
MiscBlocks.push_back(PC);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Comment::BlockCommandCommentKind: {
|
|
|
|
const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
|
|
|
|
StringRef CommandName = BCC->getCommandName();
|
|
|
|
if (!Brief && (CommandName == "brief" || CommandName == "short")) {
|
|
|
|
Brief = BCC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!Returns && (CommandName == "returns" || CommandName == "return")) {
|
|
|
|
Returns = BCC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
MiscBlocks.push_back(BCC);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Comment::ParamCommandCommentKind: {
|
|
|
|
const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
|
|
|
|
if (!PCC->hasParamName())
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
|
|
|
|
break;
|
|
|
|
|
|
|
|
Params.push_back(PCC);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Comment::VerbatimBlockCommentKind:
|
|
|
|
case Comment::VerbatimLineCommentKind:
|
|
|
|
MiscBlocks.push_back(cast<BlockCommandComment>(Child));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Comment::TextCommentKind:
|
|
|
|
case Comment::InlineCommandCommentKind:
|
|
|
|
case Comment::HTMLStartTagCommentKind:
|
|
|
|
case Comment::HTMLEndTagCommentKind:
|
|
|
|
case Comment::VerbatimBlockLineCommentKind:
|
|
|
|
case Comment::FullCommentKind:
|
|
|
|
llvm_unreachable("AST node of this kind can't be a child of "
|
|
|
|
"a FullComment");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort params in order they are declared in the function prototype.
|
|
|
|
// Unresolved parameters are put at the end of the list in the same order
|
|
|
|
// they were seen in the comment.
|
|
|
|
std::stable_sort(Params.begin(), Params.end(),
|
|
|
|
ParamCommandCommentCompareIndex());
|
|
|
|
|
|
|
|
bool FirstParagraphIsBrief = false;
|
|
|
|
if (Brief)
|
|
|
|
visit(Brief);
|
|
|
|
else if (FirstParagraph) {
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<p class=\"para-brief\">";
|
2012-07-21 05:34:34 +08:00
|
|
|
visitNonStandaloneParagraphComment(FirstParagraph);
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "</p>";
|
2012-07-21 05:34:34 +08:00
|
|
|
FirstParagraphIsBrief = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = MiscBlocks.size(); i != e; ++i) {
|
|
|
|
const Comment *C = MiscBlocks[i];
|
|
|
|
if (FirstParagraphIsBrief && C == FirstParagraph)
|
|
|
|
continue;
|
|
|
|
visit(C);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Params.size() != 0) {
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<dl>";
|
2012-07-21 05:34:34 +08:00
|
|
|
for (unsigned i = 0, e = Params.size(); i != e; ++i)
|
|
|
|
visit(Params[i]);
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "</dl>";
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Returns)
|
|
|
|
visit(Returns);
|
2012-07-21 09:47:43 +08:00
|
|
|
|
|
|
|
Result.flush();
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
|
|
|
|
const ParagraphComment *C) {
|
|
|
|
if (!C)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
visit(*I);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
|
|
|
|
for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
|
|
|
|
const char C = *I;
|
|
|
|
switch (C) {
|
|
|
|
case '&':
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "&";
|
2012-07-21 05:34:34 +08:00
|
|
|
break;
|
|
|
|
case '<':
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "<";
|
2012-07-21 05:34:34 +08:00
|
|
|
break;
|
|
|
|
case '>':
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << ">";
|
2012-07-21 05:34:34 +08:00
|
|
|
break;
|
|
|
|
case '"':
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << """;
|
2012-07-21 05:34:34 +08:00
|
|
|
break;
|
|
|
|
case '\'':
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "'";
|
2012-07-21 05:34:34 +08:00
|
|
|
break;
|
|
|
|
case '/':
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << "/";
|
2012-07-21 05:34:34 +08:00
|
|
|
break;
|
|
|
|
default:
|
2012-07-21 09:47:43 +08:00
|
|
|
Result << C;
|
2012-07-21 05:34:34 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
|
|
|
|
const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
|
|
|
|
if (!HTC)
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
2012-07-21 09:47:43 +08:00
|
|
|
SmallString<128> HTML;
|
|
|
|
CommentASTToHTMLConverter Converter(HTML);
|
2012-07-21 05:34:34 +08:00
|
|
|
Converter.visit(HTC);
|
2012-07-21 09:47:43 +08:00
|
|
|
return createCXString(HTML.str(), /* DupString = */ true);
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CXString clang_FullComment_getAsHTML(CXComment CXC) {
|
|
|
|
const FullComment *FC = getASTNodeAs<FullComment>(CXC);
|
|
|
|
if (!FC)
|
|
|
|
return createCXString((const char *) 0);
|
|
|
|
|
2012-07-21 09:47:43 +08:00
|
|
|
SmallString<1024> HTML;
|
|
|
|
CommentASTToHTMLConverter Converter(HTML);
|
2012-07-21 05:34:34 +08:00
|
|
|
Converter.visit(FC);
|
2012-07-21 09:47:43 +08:00
|
|
|
return createCXString(HTML.str(), /* DupString = */ true);
|
2012-07-21 05:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // end extern "C"
|
|
|
|
|