(N)); break; case ASTNodeKind::TextAndInline: printTextAndInline(cast(N)); break; case ASTNodeKind::PrivateExtension: llvm_unreachable("implement"); } } void printParagraph(const Paragraph *P) { printTextAndInline(P->getContent()); } void printBulletList(const BulletList *BL) { printRawHTML(" "); for (unsigned i = 0, e = BL->getNumItems(); i != e; ++i) { printRawHTML("
"); } void printEnumeratedList(const EnumeratedList *EL) { printRawHTML("- "); for (const auto *N : BL->getItemChildren(i)) { printASTNode(N); } printRawHTML("
"); } printRawHTML(""); for (unsigned i = 0, e = EL->getNumItems(); i != e; ++i) { printRawHTML("
"); } void printDefinitionListItem(const DefinitionListItem *DLI) { printRawHTML("- "); for (const auto *N : EL->getItemChildren(i)) { printASTNode(N); } printRawHTML("
"); } printRawHTML(""); printASTNode(DLI->getTerm()); printRawHTML(" "); for (const auto *N : DLI->getClassifiers()) { printASTNode(N); } printRawHTML(""); for (const auto *N : DLI->getDefinitionChildren()) { printASTNode(N); } printRawHTML(" "); } void printDefinitionList(const DefinitionList *DL) { printRawHTML(""); for (const auto *N : DL->getChildren()) { printASTNode(N); } printRawHTML("
"); } void printField(const Field *F) { printRawHTML(""); printASTNode(F->getName()); printRawHTML(" "); printRawHTML(""); for (const auto *N : F->getBodyChildren()) { printASTNode(N); } printRawHTML(" "); } void printFieldList(const FieldList *FL) { printRawHTML(""); for (const auto *F : FL->getChildren()) { printASTNode(F); } printRawHTML("
"); } void printBlockQuote(const BlockQuote *BQ) { printRawHTML(""); for (const auto *N : BQ->getChildren()) { printASTNode(N); } printRawHTML(""); } void printTextAndInline(const TextAndInline *T) { if (T->isLinePart()) { LinePart LP = T->getLinePart(); appendWithXMLEscaping(OS, LP.Text); } else { LineListRef LL = T->getLines(); for (unsigned i = 0, e = LL.size(); i != e; ++i) { appendWithXMLEscaping(OS, LL[i].Text.drop_front(LL[i].FirstTextByte)); if (i != e - 1) OS << " "; } } } void printOrphanField(const Field *F) { printRawHTML(""); printField(F); printRawHTML("
"); } void printAsParameter(const comments::ParamField *PF) { OS << ""; } void printAsReturns(const Field *F) { for (const auto *N : F->getBodyChildren()) { printASTNode(N); } } void visitFullComment(const FullComment *FC); }; } // unnamed namespace void CommentToXMLConverter::visitFullComment(const FullComment *FC) { const Decl *D = FC->getDecl(); const auto &Parts = FC->getParts(TheCommentContext); StringRef RootEndTag; if (isa "; OS << PF->getParamName().Text; OS << " in "; for (const auto *N : PF->getBodyChildren()) { OS << " "; printASTNode(N); OS << " "; } OS << "(D)) { OS << " (D) || isa (D) || isa (D)) { OS << " getLoc(); if (Loc.isValid()) { const auto &SM = D->getASTContext().SourceMgr; unsigned BufferID = SM.findBufferContainingLoc(Loc); StringRef FileName = SM->getMemoryBuffer(BufferID)->getBufferIdentifier(); auto LineAndColumn = SM.getLineAndColumn(Loc); OS << " file=\""; appendWithXMLEscaping(OS, FileName); OS << "\""; OS << " line=\"" << LineAndColumn.first << "\" column=\"" << LineAndColumn.second << "\""; } } // Finish the root tag. OS << ">"; auto *VD = dyn_cast (D); OS << " "; if (VD && VD->hasName()) OS << VD->getFullName(); OS << " "; if (VD) { llvm::SmallString<64> SS; bool Failed; { llvm::raw_svector_ostream OS(SS); Failed = ide::printDeclUSR(VD, OS); } if (!Failed && !SS.empty()) { OS << "" << SS << " "; } } { PrintOptions PO; PO.PrintDefaultParameterPlaceholder = true; PO.SkipImplicit = true; PO.PrintImplicitAttrs = false; PO.PrintUncheckedOptionalInImportedDecls = false; PO.PrintFunctionRepresentationAttrs = false; OS << ""; D->print(OS, PO); OS << " "; } if (Parts.Brief) { OS << ""; OS << " "; } if (!Parts.MiscTopLevelNodes.empty()) { OS << ""; printASTNode(Parts.Brief); OS << " "; OS << ""; for (const auto *N : Parts.MiscTopLevelNodes) { OS << " "; } if (!Parts.Params.empty()) { OS << ""; if (const auto *F = dyn_cast "; continue; } printASTNode(N); OS << ""; } OS << "(N)) { printOrphanField(F); OS << " "; for (const auto *N : Parts.Params) { printAsParameter(N); } OS << " "; } if (!Parts.Returns.empty()) { OS << ""; for (const auto *N : Parts.Returns) { OS << " "; } OS << RootEndTag; } static bool getClangDocumentationCommentAsXML(const clang::Decl *D, raw_ostream &OS) { const auto &ClangContext = D->getASTContext(); const clang::comments::FullComment *FC = ClangContext.getCommentForDecl(D, /*PP=*/nullptr); if (!FC) return false; // FIXME: hang the converter object somewhere so that it is persistent // between requests to this AST. clang::index::CommentToXMLConverter Converter; llvm::SmallString<1024> XML; Converter.convertCommentToXML(FC, XML, ClangContext); OS << XML; return true; } bool ide::getDocumentationCommentAsXML(const Decl *D, raw_ostream &OS) { auto MaybeClangNode = D->getClangNode(); if (MaybeClangNode) { if (auto *CD = MaybeClangNode.getAsDecl()) return getClangDocumentationCommentAsXML(CD, OS); return false; } CommentContext TheCommentContext; auto *FC = getFullComment(TheCommentContext, D); if (!FC) return false; CommentToXMLConverter Converter(TheCommentContext, OS); Converter.visitFullComment(FC); OS.flush(); return true; } //===----------------------------------------------------------------------===// // Conversion to Doxygen. //===----------------------------------------------------------------------===// namespace { struct CommentToDoxygenConverter { CommentContext &TheCommentContext; raw_ostream &OS; unsigned PendingNewlines = 1; CommentToDoxygenConverter(CommentContext &TheCommentContext, raw_ostream &OS) : TheCommentContext(TheCommentContext), OS(OS) {} void print(StringRef Text) { for (unsigned i = 0; i != PendingNewlines; ++i) { OS << "\n///"; if (i == PendingNewlines - 1) OS << " "; } PendingNewlines = 0; OS << Text; } void printNewline() { PendingNewlines++; } void printASTNode(const ReSTASTNode *N) { switch (N->getKind()) { case ASTNodeKind::Document: llvm_unreachable("should never happen"); break; case ASTNodeKind::Section: case ASTNodeKind::Topic: case ASTNodeKind::Sidebar: case ASTNodeKind::Title: case ASTNodeKind::Subtitle: case ASTNodeKind::Transition: llvm_unreachable("implement"); case ASTNodeKind::Paragraph: printParagraph(cast"; printAsReturns(N); OS << " "; } OS << "(N)); break; case ASTNodeKind::BulletList: printBulletList(cast (N)); break; case ASTNodeKind::EnumeratedList: printEnumeratedList(cast (N)); break; case ASTNodeKind::DefinitionListItem: printDefinitionListItem(cast (N)); break; case ASTNodeKind::DefinitionList: printDefinitionList(cast (N)); break; case ASTNodeKind::Field: printField(cast (N)); break; case ASTNodeKind::FieldList: printFieldList(cast (N)); break; case ASTNodeKind::BlockQuote: printBlockQuote(cast (N)); break; case ASTNodeKind::TextAndInline: printTextAndInline(cast(N)); break; case ASTNodeKind::PrivateExtension: llvm_unreachable("implement"); } } void printParagraph(const Paragraph *P) { print(" "); printTextAndInline(P->getContent()); print("
"); } void printBulletList(const BulletList *BL) { print(""); for (unsigned i = 0, e = BL->getNumItems(); i != e; ++i) { print("
"); } void printEnumeratedList(const EnumeratedList *EL) { print("- "); for (const auto *N : BL->getItemChildren(i)) { printASTNode(N); } print("
"); } print(""); for (unsigned i = 0, e = EL->getNumItems(); i != e; ++i) { print("
"); } void printDefinitionListItem(const DefinitionListItem *DLI) { print("- "); for (const auto *N : EL->getItemChildren(i)) { printASTNode(N); } print("
"); } print(""); printASTNode(DLI->getTerm()); for (const auto *N : DLI->getClassifiers()) { printASTNode(N); } print(" "); print(""); for (const auto *N : DLI->getDefinitionChildren()) { printASTNode(N); } print(" "); } void printDefinitionList(const DefinitionList *DL) { print(""); for (const auto *N : DL->getChildren()) { printASTNode(N); } print("
"); } void printField(const Field *F) { print(""); printASTNode(F->getName()); print(" "); print(""); for (const auto *N : F->getBodyChildren()) { printASTNode(N); } print(" "); } void printFieldList(const FieldList *FL) { print(""); for (const auto *F : FL->getChildren()) { printASTNode(F); } print("
"); } void printBlockQuote(const BlockQuote *BQ) { print(""); for (const auto *N : BQ->getChildren()) { printASTNode(N); } print(""); } void printTextAndInline(const TextAndInline *T) { if (T->isLinePart()) { LinePart LP = T->getLinePart(); print(LP.Text); } else { LineListRef LL = T->getLines(); for (unsigned i = 0, e = LL.size(); i != e; ++i) { print(LL[i].Text.drop_front(LL[i].FirstTextByte)); if (i != e - 1) printNewline(); } } } void printOrphanField(const Field *F) { print(""); printField(F); print("
"); } void printBlockCommandContent(ArrayRefNodes) { if (Nodes.size() == 0) return; print(" "); if (Nodes.size() == 1) { if (const auto *P = dyn_cast (Nodes[0])) { printTextAndInline(P->getContent()); return; } } for (const auto *N : Nodes) { printASTNode(N); } } void printAsDoxygenParam(const comments::ParamField *PF) { print("\\param "); print(PF->getParamName().Text); printBlockCommandContent(PF->getBodyChildren()); printNewline(); } void printAsDoxygenReturns(const Field *F) { print("\\returns"); printBlockCommandContent(F->getBodyChildren()); printNewline(); } }; } // unnamed namespace void ide::getDocumentationCommentAsDoxygen(CommentContext &TheCommentContext, const FullComment *FC, raw_ostream &OS) { CommentToDoxygenConverter Converter(TheCommentContext, OS); const auto &Parts = FC->getParts(TheCommentContext); if (Parts.Brief) { Converter.printTextAndInline(Parts.Brief->getContent()); Converter.printNewline(); Converter.printNewline(); } for (const auto *N : Parts.MiscTopLevelNodes) { if (const auto *F = dyn_cast (N)) { Converter.printOrphanField(F); Converter.printNewline(); continue; } if (const auto *P = dyn_cast (N)) { Converter.printTextAndInline(P->getContent()); Converter.printNewline(); Converter.printNewline(); continue; } Converter.printASTNode(N); Converter.printNewline(); } for (const auto *N : Parts.Params) { Converter.printAsDoxygenParam(N); Converter.printNewline(); } for (const auto *N : Parts.Returns) { Converter.printAsDoxygenReturns(N); Converter.printNewline(); } if (Converter.PendingNewlines != 0) OS << "\n"; }