| //===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines all libclang APIs related to walking comment AST. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CXComment.h" |
| #include "CXCursor.h" |
| #include "CXString.h" |
| #include "clang-c/Documentation.h" |
| #include "clang-c/Index.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/Index/CommentToXML.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include <climits> |
| |
| using namespace clang; |
| using namespace clang::comments; |
| using namespace clang::cxcomment; |
| |
| CXComment clang_Cursor_getParsedComment(CXCursor C) { |
| using namespace clang::cxcursor; |
| |
| if (!clang_isDeclaration(C.kind)) |
| return createCXComment(nullptr, nullptr); |
| |
| const Decl *D = getCursorDecl(C); |
| const ASTContext &Context = getCursorContext(C); |
| const FullComment *FC = Context.getCommentForDecl(D, /*PP=*/nullptr); |
| |
| return createCXComment(FC, getCursorTU(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::TParamCommandCommentKind: |
| return CXComment_TParamCommand; |
| |
| 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(nullptr, nullptr); |
| |
| return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit); |
| } |
| |
| 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 cxstring::createNull(); |
| |
| return cxstring::createRef(TC->getText()); |
| } |
| |
| CXString clang_InlineCommandComment_getCommandName(CXComment CXC) { |
| const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); |
| if (!ICC) |
| return cxstring::createNull(); |
| |
| const CommandTraits &Traits = getCommandTraits(CXC); |
| return cxstring::createRef(ICC->getCommandName(Traits)); |
| } |
| |
| 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; |
| |
| case InlineCommandComment::RenderAnchor: |
| return CXCommentInlineCommandRenderKind_Anchor; |
| } |
| llvm_unreachable("unknown InlineCommandComment::RenderKind"); |
| } |
| |
| 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 cxstring::createNull(); |
| |
| return cxstring::createRef(ICC->getArgText(ArgIdx)); |
| } |
| |
| CXString clang_HTMLTagComment_getTagName(CXComment CXC) { |
| const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC); |
| if (!HTC) |
| return cxstring::createNull(); |
| |
| return cxstring::createRef(HTC->getTagName()); |
| } |
| |
| 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 cxstring::createNull(); |
| |
| return cxstring::createRef(HST->getAttr(AttrIdx).Name); |
| } |
| |
| CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) { |
| const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); |
| if (!HST || AttrIdx >= HST->getNumAttrs()) |
| return cxstring::createNull(); |
| |
| return cxstring::createRef(HST->getAttr(AttrIdx).Value); |
| } |
| |
| CXString clang_BlockCommandComment_getCommandName(CXComment CXC) { |
| const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); |
| if (!BCC) |
| return cxstring::createNull(); |
| |
| const CommandTraits &Traits = getCommandTraits(CXC); |
| return cxstring::createRef(BCC->getCommandName(Traits)); |
| } |
| |
| 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 cxstring::createNull(); |
| |
| return cxstring::createRef(BCC->getArgText(ArgIdx)); |
| } |
| |
| CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) { |
| const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); |
| if (!BCC) |
| return createCXComment(nullptr, nullptr); |
| |
| return createCXComment(BCC->getParagraph(), CXC.TranslationUnit); |
| } |
| |
| CXString clang_ParamCommandComment_getParamName(CXComment CXC) { |
| const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); |
| if (!PCC || !PCC->hasParamName()) |
| return cxstring::createNull(); |
| |
| return cxstring::createRef(PCC->getParamNameAsWritten()); |
| } |
| |
| 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); |
| if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam()) |
| 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_TParamCommandComment_getParamName(CXComment CXC) { |
| const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); |
| if (!TPCC || !TPCC->hasParamName()) |
| return cxstring::createNull(); |
| |
| return cxstring::createRef(TPCC->getParamNameAsWritten()); |
| } |
| |
| unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) { |
| const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); |
| if (!TPCC) |
| return false; |
| |
| return TPCC->isPositionValid(); |
| } |
| |
| unsigned clang_TParamCommandComment_getDepth(CXComment CXC) { |
| const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); |
| if (!TPCC || !TPCC->isPositionValid()) |
| return 0; |
| |
| return TPCC->getDepth(); |
| } |
| |
| unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) { |
| const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); |
| if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth()) |
| return 0; |
| |
| return TPCC->getIndex(Depth); |
| } |
| |
| CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) { |
| const VerbatimBlockLineComment *VBL = |
| getASTNodeAs<VerbatimBlockLineComment>(CXC); |
| if (!VBL) |
| return cxstring::createNull(); |
| |
| return cxstring::createRef(VBL->getText()); |
| } |
| |
| CXString clang_VerbatimLineComment_getText(CXComment CXC) { |
| const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC); |
| if (!VLC) |
| return cxstring::createNull(); |
| |
| return cxstring::createRef(VLC->getText()); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Converting comments to XML. |
| //===----------------------------------------------------------------------===// |
| |
| CXString clang_HTMLTagComment_getAsString(CXComment CXC) { |
| const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC); |
| if (!HTC) |
| return cxstring::createNull(); |
| |
| CXTranslationUnit TU = CXC.TranslationUnit; |
| if (!TU->CommentToXML) |
| TU->CommentToXML = new clang::index::CommentToXMLConverter(); |
| |
| SmallString<128> Text; |
| TU->CommentToXML->convertHTMLTagNodeToText( |
| HTC, Text, cxtu::getASTUnit(TU)->getASTContext()); |
| return cxstring::createDup(Text.str()); |
| } |
| |
| CXString clang_FullComment_getAsHTML(CXComment CXC) { |
| const FullComment *FC = getASTNodeAs<FullComment>(CXC); |
| if (!FC) |
| return cxstring::createNull(); |
| |
| CXTranslationUnit TU = CXC.TranslationUnit; |
| if (!TU->CommentToXML) |
| TU->CommentToXML = new clang::index::CommentToXMLConverter(); |
| |
| SmallString<1024> HTML; |
| TU->CommentToXML |
| ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext()); |
| return cxstring::createDup(HTML.str()); |
| } |
| |
| CXString clang_FullComment_getAsXML(CXComment CXC) { |
| const FullComment *FC = getASTNodeAs<FullComment>(CXC); |
| if (!FC) |
| return cxstring::createNull(); |
| |
| CXTranslationUnit TU = CXC.TranslationUnit; |
| if (!TU->CommentToXML) |
| TU->CommentToXML = new clang::index::CommentToXMLConverter(); |
| |
| SmallString<1024> XML; |
| TU->CommentToXML |
| ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext()); |
| return cxstring::createDup(XML.str()); |
| } |
| |