Home | History | Annotate | Line # | Download | only in libclang
      1 //===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file defines all libclang APIs related to walking comment AST.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #include "CXComment.h"
     14 #include "CXCursor.h"
     15 #include "CXString.h"
     16 #include "clang-c/Documentation.h"
     17 #include "clang-c/Index.h"
     18 #include "clang/AST/Decl.h"
     19 #include "clang/Index/CommentToXML.h"
     20 #include "llvm/ADT/StringExtras.h"
     21 #include "llvm/Support/ErrorHandling.h"
     22 #include <climits>
     23 
     24 using namespace clang;
     25 using namespace clang::comments;
     26 using namespace clang::cxcomment;
     27 
     28 CXComment clang_Cursor_getParsedComment(CXCursor C) {
     29   using namespace clang::cxcursor;
     30 
     31   if (!clang_isDeclaration(C.kind))
     32     return createCXComment(nullptr, nullptr);
     33 
     34   const Decl *D = getCursorDecl(C);
     35   const ASTContext &Context = getCursorContext(C);
     36   const FullComment *FC = Context.getCommentForDecl(D, /*PP=*/nullptr);
     37 
     38   return createCXComment(FC, getCursorTU(C));
     39 }
     40 
     41 enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
     42   const Comment *C = getASTNode(CXC);
     43   if (!C)
     44     return CXComment_Null;
     45 
     46   switch (C->getCommentKind()) {
     47   case Comment::NoCommentKind:
     48     return CXComment_Null;
     49 
     50   case Comment::TextCommentKind:
     51     return CXComment_Text;
     52 
     53   case Comment::InlineCommandCommentKind:
     54     return CXComment_InlineCommand;
     55 
     56   case Comment::HTMLStartTagCommentKind:
     57     return CXComment_HTMLStartTag;
     58 
     59   case Comment::HTMLEndTagCommentKind:
     60     return CXComment_HTMLEndTag;
     61 
     62   case Comment::ParagraphCommentKind:
     63     return CXComment_Paragraph;
     64 
     65   case Comment::BlockCommandCommentKind:
     66     return CXComment_BlockCommand;
     67 
     68   case Comment::ParamCommandCommentKind:
     69     return CXComment_ParamCommand;
     70 
     71   case Comment::TParamCommandCommentKind:
     72     return CXComment_TParamCommand;
     73 
     74   case Comment::VerbatimBlockCommentKind:
     75     return CXComment_VerbatimBlockCommand;
     76 
     77   case Comment::VerbatimBlockLineCommentKind:
     78     return CXComment_VerbatimBlockLine;
     79 
     80   case Comment::VerbatimLineCommentKind:
     81     return CXComment_VerbatimLine;
     82 
     83   case Comment::FullCommentKind:
     84     return CXComment_FullComment;
     85   }
     86   llvm_unreachable("unknown CommentKind");
     87 }
     88 
     89 unsigned clang_Comment_getNumChildren(CXComment CXC) {
     90   const Comment *C = getASTNode(CXC);
     91   if (!C)
     92     return 0;
     93 
     94   return C->child_count();
     95 }
     96 
     97 CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
     98   const Comment *C = getASTNode(CXC);
     99   if (!C || ChildIdx >= C->child_count())
    100     return createCXComment(nullptr, nullptr);
    101 
    102   return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit);
    103 }
    104 
    105 unsigned clang_Comment_isWhitespace(CXComment CXC) {
    106   const Comment *C = getASTNode(CXC);
    107   if (!C)
    108     return false;
    109 
    110   if (const TextComment *TC = dyn_cast<TextComment>(C))
    111     return TC->isWhitespace();
    112 
    113   if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
    114     return PC->isWhitespace();
    115 
    116   return false;
    117 }
    118 
    119 unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
    120   const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
    121   if (!ICC)
    122     return false;
    123 
    124   return ICC->hasTrailingNewline();
    125 }
    126 
    127 CXString clang_TextComment_getText(CXComment CXC) {
    128   const TextComment *TC = getASTNodeAs<TextComment>(CXC);
    129   if (!TC)
    130     return cxstring::createNull();
    131 
    132   return cxstring::createRef(TC->getText());
    133 }
    134 
    135 CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
    136   const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
    137   if (!ICC)
    138     return cxstring::createNull();
    139 
    140   const CommandTraits &Traits = getCommandTraits(CXC);
    141   return cxstring::createRef(ICC->getCommandName(Traits));
    142 }
    143 
    144 enum CXCommentInlineCommandRenderKind
    145 clang_InlineCommandComment_getRenderKind(CXComment CXC) {
    146   const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
    147   if (!ICC)
    148     return CXCommentInlineCommandRenderKind_Normal;
    149 
    150   switch (ICC->getRenderKind()) {
    151   case InlineCommandComment::RenderNormal:
    152     return CXCommentInlineCommandRenderKind_Normal;
    153 
    154   case InlineCommandComment::RenderBold:
    155     return CXCommentInlineCommandRenderKind_Bold;
    156 
    157   case InlineCommandComment::RenderMonospaced:
    158     return CXCommentInlineCommandRenderKind_Monospaced;
    159 
    160   case InlineCommandComment::RenderEmphasized:
    161     return CXCommentInlineCommandRenderKind_Emphasized;
    162 
    163   case InlineCommandComment::RenderAnchor:
    164     return CXCommentInlineCommandRenderKind_Anchor;
    165   }
    166   llvm_unreachable("unknown InlineCommandComment::RenderKind");
    167 }
    168 
    169 unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
    170   const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
    171   if (!ICC)
    172     return 0;
    173 
    174   return ICC->getNumArgs();
    175 }
    176 
    177 CXString clang_InlineCommandComment_getArgText(CXComment CXC,
    178                                                unsigned ArgIdx) {
    179   const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
    180   if (!ICC || ArgIdx >= ICC->getNumArgs())
    181     return cxstring::createNull();
    182 
    183   return cxstring::createRef(ICC->getArgText(ArgIdx));
    184 }
    185 
    186 CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
    187   const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
    188   if (!HTC)
    189     return cxstring::createNull();
    190 
    191   return cxstring::createRef(HTC->getTagName());
    192 }
    193 
    194 unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
    195   const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
    196   if (!HST)
    197     return false;
    198 
    199   return HST->isSelfClosing();
    200 }
    201 
    202 unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
    203   const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
    204   if (!HST)
    205     return 0;
    206 
    207   return HST->getNumAttrs();
    208 }
    209 
    210 CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
    211   const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
    212   if (!HST || AttrIdx >= HST->getNumAttrs())
    213     return cxstring::createNull();
    214 
    215   return cxstring::createRef(HST->getAttr(AttrIdx).Name);
    216 }
    217 
    218 CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
    219   const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
    220   if (!HST || AttrIdx >= HST->getNumAttrs())
    221     return cxstring::createNull();
    222 
    223   return cxstring::createRef(HST->getAttr(AttrIdx).Value);
    224 }
    225 
    226 CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
    227   const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
    228   if (!BCC)
    229     return cxstring::createNull();
    230 
    231   const CommandTraits &Traits = getCommandTraits(CXC);
    232   return cxstring::createRef(BCC->getCommandName(Traits));
    233 }
    234 
    235 unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
    236   const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
    237   if (!BCC)
    238     return 0;
    239 
    240   return BCC->getNumArgs();
    241 }
    242 
    243 CXString clang_BlockCommandComment_getArgText(CXComment CXC,
    244                                               unsigned ArgIdx) {
    245   const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
    246   if (!BCC || ArgIdx >= BCC->getNumArgs())
    247     return cxstring::createNull();
    248 
    249   return cxstring::createRef(BCC->getArgText(ArgIdx));
    250 }
    251 
    252 CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
    253   const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
    254   if (!BCC)
    255     return createCXComment(nullptr, nullptr);
    256 
    257   return createCXComment(BCC->getParagraph(), CXC.TranslationUnit);
    258 }
    259 
    260 CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
    261   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
    262   if (!PCC || !PCC->hasParamName())
    263     return cxstring::createNull();
    264 
    265   return cxstring::createRef(PCC->getParamNameAsWritten());
    266 }
    267 
    268 unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
    269   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
    270   if (!PCC)
    271     return false;
    272 
    273   return PCC->isParamIndexValid();
    274 }
    275 
    276 unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
    277   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
    278   if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam())
    279     return ParamCommandComment::InvalidParamIndex;
    280 
    281   return PCC->getParamIndex();
    282 }
    283 
    284 unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
    285   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
    286   if (!PCC)
    287     return false;
    288 
    289   return PCC->isDirectionExplicit();
    290 }
    291 
    292 enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
    293                                                             CXComment CXC) {
    294   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
    295   if (!PCC)
    296     return CXCommentParamPassDirection_In;
    297 
    298   switch (PCC->getDirection()) {
    299   case ParamCommandComment::In:
    300     return CXCommentParamPassDirection_In;
    301 
    302   case ParamCommandComment::Out:
    303     return CXCommentParamPassDirection_Out;
    304 
    305   case ParamCommandComment::InOut:
    306     return CXCommentParamPassDirection_InOut;
    307   }
    308   llvm_unreachable("unknown ParamCommandComment::PassDirection");
    309 }
    310 
    311 CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
    312   const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
    313   if (!TPCC || !TPCC->hasParamName())
    314     return cxstring::createNull();
    315 
    316   return cxstring::createRef(TPCC->getParamNameAsWritten());
    317 }
    318 
    319 unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
    320   const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
    321   if (!TPCC)
    322     return false;
    323 
    324   return TPCC->isPositionValid();
    325 }
    326 
    327 unsigned clang_TParamCommandComment_getDepth(CXComment CXC) {
    328   const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
    329   if (!TPCC || !TPCC->isPositionValid())
    330     return 0;
    331 
    332   return TPCC->getDepth();
    333 }
    334 
    335 unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) {
    336   const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
    337   if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth())
    338     return 0;
    339 
    340   return TPCC->getIndex(Depth);
    341 }
    342 
    343 CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
    344   const VerbatimBlockLineComment *VBL =
    345       getASTNodeAs<VerbatimBlockLineComment>(CXC);
    346   if (!VBL)
    347     return cxstring::createNull();
    348 
    349   return cxstring::createRef(VBL->getText());
    350 }
    351 
    352 CXString clang_VerbatimLineComment_getText(CXComment CXC) {
    353   const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
    354   if (!VLC)
    355     return cxstring::createNull();
    356 
    357   return cxstring::createRef(VLC->getText());
    358 }
    359 
    360 //===----------------------------------------------------------------------===//
    361 // Converting comments to XML.
    362 //===----------------------------------------------------------------------===//
    363 
    364 CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
    365   const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
    366   if (!HTC)
    367     return cxstring::createNull();
    368 
    369   CXTranslationUnit TU = CXC.TranslationUnit;
    370   if (!TU->CommentToXML)
    371     TU->CommentToXML = new clang::index::CommentToXMLConverter();
    372 
    373   SmallString<128> Text;
    374   TU->CommentToXML->convertHTMLTagNodeToText(
    375       HTC, Text, cxtu::getASTUnit(TU)->getASTContext());
    376   return cxstring::createDup(Text.str());
    377 }
    378 
    379 CXString clang_FullComment_getAsHTML(CXComment CXC) {
    380   const FullComment *FC = getASTNodeAs<FullComment>(CXC);
    381   if (!FC)
    382     return cxstring::createNull();
    383 
    384   CXTranslationUnit TU = CXC.TranslationUnit;
    385   if (!TU->CommentToXML)
    386     TU->CommentToXML = new clang::index::CommentToXMLConverter();
    387 
    388   SmallString<1024> HTML;
    389   TU->CommentToXML
    390       ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext());
    391   return cxstring::createDup(HTML.str());
    392 }
    393 
    394 CXString clang_FullComment_getAsXML(CXComment CXC) {
    395   const FullComment *FC = getASTNodeAs<FullComment>(CXC);
    396   if (!FC)
    397     return cxstring::createNull();
    398 
    399   CXTranslationUnit TU = CXC.TranslationUnit;
    400   if (!TU->CommentToXML)
    401     TU->CommentToXML = new clang::index::CommentToXMLConverter();
    402 
    403   SmallString<1024> XML;
    404   TU->CommentToXML
    405       ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext());
    406   return cxstring::createDup(XML.str());
    407 }
    408 
    409