Home | History | Annotate | Line # | Download | only in AST
      1 //===--- Comment.cpp - Comment AST node implementation --------------------===//
      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 #include "clang/AST/Comment.h"
     10 #include "clang/AST/ASTContext.h"
     11 #include "clang/AST/Decl.h"
     12 #include "clang/AST/DeclObjC.h"
     13 #include "clang/AST/DeclTemplate.h"
     14 #include "clang/Basic/CharInfo.h"
     15 #include "llvm/Support/ErrorHandling.h"
     16 #include <type_traits>
     17 
     18 namespace clang {
     19 namespace comments {
     20 
     21 // Check that no comment class has a non-trival destructor. They are allocated
     22 // with a BumpPtrAllocator and therefore their destructor is not executed.
     23 #define ABSTRACT_COMMENT(COMMENT)
     24 #define COMMENT(CLASS, PARENT)                                                 \
     25   static_assert(std::is_trivially_destructible<CLASS>::value,                  \
     26                 #CLASS " should be trivially destructible!");
     27 #include "clang/AST/CommentNodes.inc"
     28 #undef COMMENT
     29 #undef ABSTRACT_COMMENT
     30 
     31 // DeclInfo is also allocated with a BumpPtrAllocator.
     32 static_assert(std::is_trivially_destructible<DeclInfo>::value,
     33               "DeclInfo should be trivially destructible!");
     34 
     35 const char *Comment::getCommentKindName() const {
     36   switch (getCommentKind()) {
     37   case NoCommentKind: return "NoCommentKind";
     38 #define ABSTRACT_COMMENT(COMMENT)
     39 #define COMMENT(CLASS, PARENT) \
     40   case CLASS##Kind: \
     41     return #CLASS;
     42 #include "clang/AST/CommentNodes.inc"
     43 #undef COMMENT
     44 #undef ABSTRACT_COMMENT
     45   }
     46   llvm_unreachable("Unknown comment kind!");
     47 }
     48 
     49 namespace {
     50 struct good {};
     51 struct bad {};
     52 
     53 template <typename T>
     54 good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
     55   return good();
     56 }
     57 
     58 LLVM_ATTRIBUTE_UNUSED
     59 static inline bad implements_child_begin_end(
     60                       Comment::child_iterator (Comment::*)() const) {
     61   return bad();
     62 }
     63 
     64 #define ASSERT_IMPLEMENTS_child_begin(function) \
     65   (void) good(implements_child_begin_end(function))
     66 
     67 LLVM_ATTRIBUTE_UNUSED
     68 static inline void CheckCommentASTNodes() {
     69 #define ABSTRACT_COMMENT(COMMENT)
     70 #define COMMENT(CLASS, PARENT) \
     71   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \
     72   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);
     73 #include "clang/AST/CommentNodes.inc"
     74 #undef COMMENT
     75 #undef ABSTRACT_COMMENT
     76 }
     77 
     78 #undef ASSERT_IMPLEMENTS_child_begin
     79 
     80 } // end unnamed namespace
     81 
     82 Comment::child_iterator Comment::child_begin() const {
     83   switch (getCommentKind()) {
     84   case NoCommentKind: llvm_unreachable("comment without a kind");
     85 #define ABSTRACT_COMMENT(COMMENT)
     86 #define COMMENT(CLASS, PARENT) \
     87   case CLASS##Kind: \
     88     return static_cast<const CLASS *>(this)->child_begin();
     89 #include "clang/AST/CommentNodes.inc"
     90 #undef COMMENT
     91 #undef ABSTRACT_COMMENT
     92   }
     93   llvm_unreachable("Unknown comment kind!");
     94 }
     95 
     96 Comment::child_iterator Comment::child_end() const {
     97   switch (getCommentKind()) {
     98   case NoCommentKind: llvm_unreachable("comment without a kind");
     99 #define ABSTRACT_COMMENT(COMMENT)
    100 #define COMMENT(CLASS, PARENT) \
    101   case CLASS##Kind: \
    102     return static_cast<const CLASS *>(this)->child_end();
    103 #include "clang/AST/CommentNodes.inc"
    104 #undef COMMENT
    105 #undef ABSTRACT_COMMENT
    106   }
    107   llvm_unreachable("Unknown comment kind!");
    108 }
    109 
    110 bool TextComment::isWhitespaceNoCache() const {
    111   for (StringRef::const_iterator I = Text.begin(), E = Text.end();
    112        I != E; ++I) {
    113     if (!clang::isWhitespace(*I))
    114       return false;
    115   }
    116   return true;
    117 }
    118 
    119 bool ParagraphComment::isWhitespaceNoCache() const {
    120   for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
    121     if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
    122       if (!TC->isWhitespace())
    123         return false;
    124     } else
    125       return false;
    126   }
    127   return true;
    128 }
    129 
    130 static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) {
    131   TypeLoc TL = SrcTL.IgnoreParens();
    132 
    133   // Look through attribute types.
    134   if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>())
    135     return AttributeTL.getModifiedLoc();
    136   // Look through qualified types.
    137   if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>())
    138     return QualifiedTL.getUnqualifiedLoc();
    139   // Look through pointer types.
    140   if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>())
    141     return PointerTL.getPointeeLoc().getUnqualifiedLoc();
    142   // Look through reference types.
    143   if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>())
    144     return ReferenceTL.getPointeeLoc().getUnqualifiedLoc();
    145   // Look through adjusted types.
    146   if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>())
    147     return ATL.getOriginalLoc();
    148   if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>())
    149     return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
    150   if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>())
    151     return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
    152   if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>())
    153     return ETL.getNamedTypeLoc();
    154 
    155   return TL;
    156 }
    157 
    158 static bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) {
    159   TypeLoc PrevTL;
    160   while (PrevTL != TL) {
    161     PrevTL = TL;
    162     TL = lookThroughTypedefOrTypeAliasLocs(TL);
    163   }
    164 
    165   if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
    166     ResFTL = FTL;
    167     return true;
    168   }
    169 
    170   if (TemplateSpecializationTypeLoc STL =
    171           TL.getAs<TemplateSpecializationTypeLoc>()) {
    172     // If we have a typedef to a template specialization with exactly one
    173     // template argument of a function type, this looks like std::function,
    174     // boost::function, or other function wrapper.  Treat these typedefs as
    175     // functions.
    176     if (STL.getNumArgs() != 1)
    177       return false;
    178     TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0);
    179     if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type)
    180       return false;
    181     TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo();
    182     TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc();
    183     if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
    184       ResFTL = FTL;
    185       return true;
    186     }
    187   }
    188 
    189   return false;
    190 }
    191 
    192 const char *ParamCommandComment::getDirectionAsString(PassDirection D) {
    193   switch (D) {
    194   case ParamCommandComment::In:
    195     return "[in]";
    196   case ParamCommandComment::Out:
    197     return "[out]";
    198   case ParamCommandComment::InOut:
    199     return "[in,out]";
    200   }
    201   llvm_unreachable("unknown PassDirection");
    202 }
    203 
    204 void DeclInfo::fill() {
    205   assert(!IsFilled);
    206 
    207   // Set defaults.
    208   Kind = OtherKind;
    209   TemplateKind = NotTemplate;
    210   IsObjCMethod = false;
    211   IsInstanceMethod = false;
    212   IsClassMethod = false;
    213   ParamVars = None;
    214   TemplateParameters = nullptr;
    215 
    216   if (!CommentDecl) {
    217     // If there is no declaration, the defaults is our only guess.
    218     IsFilled = true;
    219     return;
    220   }
    221   CurrentDecl = CommentDecl;
    222 
    223   Decl::Kind K = CommentDecl->getKind();
    224   switch (K) {
    225   default:
    226     // Defaults are should be good for declarations we don't handle explicitly.
    227     break;
    228   case Decl::Function:
    229   case Decl::CXXMethod:
    230   case Decl::CXXConstructor:
    231   case Decl::CXXDestructor:
    232   case Decl::CXXConversion: {
    233     const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
    234     Kind = FunctionKind;
    235     ParamVars = FD->parameters();
    236     ReturnType = FD->getReturnType();
    237     unsigned NumLists = FD->getNumTemplateParameterLists();
    238     if (NumLists != 0) {
    239       TemplateKind = TemplateSpecialization;
    240       TemplateParameters =
    241           FD->getTemplateParameterList(NumLists - 1);
    242     }
    243 
    244     if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
    245         K == Decl::CXXDestructor || K == Decl::CXXConversion) {
    246       const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
    247       IsInstanceMethod = MD->isInstance();
    248       IsClassMethod = !IsInstanceMethod;
    249     }
    250     break;
    251   }
    252   case Decl::ObjCMethod: {
    253     const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
    254     Kind = FunctionKind;
    255     ParamVars = MD->parameters();
    256     ReturnType = MD->getReturnType();
    257     IsObjCMethod = true;
    258     IsInstanceMethod = MD->isInstanceMethod();
    259     IsClassMethod = !IsInstanceMethod;
    260     break;
    261   }
    262   case Decl::FunctionTemplate: {
    263     const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
    264     Kind = FunctionKind;
    265     TemplateKind = Template;
    266     const FunctionDecl *FD = FTD->getTemplatedDecl();
    267     ParamVars = FD->parameters();
    268     ReturnType = FD->getReturnType();
    269     TemplateParameters = FTD->getTemplateParameters();
    270     break;
    271   }
    272   case Decl::ClassTemplate: {
    273     const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
    274     Kind = ClassKind;
    275     TemplateKind = Template;
    276     TemplateParameters = CTD->getTemplateParameters();
    277     break;
    278   }
    279   case Decl::ClassTemplatePartialSpecialization: {
    280     const ClassTemplatePartialSpecializationDecl *CTPSD =
    281         cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
    282     Kind = ClassKind;
    283     TemplateKind = TemplatePartialSpecialization;
    284     TemplateParameters = CTPSD->getTemplateParameters();
    285     break;
    286   }
    287   case Decl::ClassTemplateSpecialization:
    288     Kind = ClassKind;
    289     TemplateKind = TemplateSpecialization;
    290     break;
    291   case Decl::Record:
    292   case Decl::CXXRecord:
    293     Kind = ClassKind;
    294     break;
    295   case Decl::Var:
    296   case Decl::Field:
    297   case Decl::EnumConstant:
    298   case Decl::ObjCIvar:
    299   case Decl::ObjCAtDefsField:
    300   case Decl::ObjCProperty: {
    301     const TypeSourceInfo *TSI;
    302     if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl))
    303       TSI = VD->getTypeSourceInfo();
    304     else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl))
    305       TSI = PD->getTypeSourceInfo();
    306     else
    307       TSI = nullptr;
    308     if (TSI) {
    309       TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
    310       FunctionTypeLoc FTL;
    311       if (getFunctionTypeLoc(TL, FTL)) {
    312         ParamVars = FTL.getParams();
    313         ReturnType = FTL.getReturnLoc().getType();
    314       }
    315     }
    316     Kind = VariableKind;
    317     break;
    318   }
    319   case Decl::Namespace:
    320     Kind = NamespaceKind;
    321     break;
    322   case Decl::TypeAlias:
    323   case Decl::Typedef: {
    324     Kind = TypedefKind;
    325     // If this is a typedef / using to something we consider a function, extract
    326     // arguments and return type.
    327     const TypeSourceInfo *TSI =
    328         K == Decl::Typedef
    329             ? cast<TypedefDecl>(CommentDecl)->getTypeSourceInfo()
    330             : cast<TypeAliasDecl>(CommentDecl)->getTypeSourceInfo();
    331     if (!TSI)
    332       break;
    333     TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
    334     FunctionTypeLoc FTL;
    335     if (getFunctionTypeLoc(TL, FTL)) {
    336       Kind = FunctionKind;
    337       ParamVars = FTL.getParams();
    338       ReturnType = FTL.getReturnLoc().getType();
    339     }
    340     break;
    341   }
    342   case Decl::TypeAliasTemplate: {
    343     const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
    344     Kind = TypedefKind;
    345     TemplateKind = Template;
    346     TemplateParameters = TAT->getTemplateParameters();
    347     TypeAliasDecl *TAD = TAT->getTemplatedDecl();
    348     if (!TAD)
    349       break;
    350 
    351     const TypeSourceInfo *TSI = TAD->getTypeSourceInfo();
    352     if (!TSI)
    353       break;
    354     TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
    355     FunctionTypeLoc FTL;
    356     if (getFunctionTypeLoc(TL, FTL)) {
    357       Kind = FunctionKind;
    358       ParamVars = FTL.getParams();
    359       ReturnType = FTL.getReturnLoc().getType();
    360     }
    361     break;
    362   }
    363   case Decl::Enum:
    364     Kind = EnumKind;
    365     break;
    366   }
    367 
    368   IsFilled = true;
    369 }
    370 
    371 StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
    372   assert(isParamIndexValid());
    373   if (isVarArgParam())
    374     return "...";
    375   return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
    376 }
    377 
    378 StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
    379   assert(isPositionValid());
    380   const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
    381   for (unsigned i = 0, e = getDepth(); i != e; ++i) {
    382     assert(TPL && "Unknown TemplateParameterList");
    383     if (i == e - 1)
    384       return TPL->getParam(getIndex(i))->getName();
    385     const NamedDecl *Param = TPL->getParam(getIndex(i));
    386     if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))
    387       TPL = TTP->getTemplateParameters();
    388   }
    389   return "";
    390 }
    391 
    392 } // end namespace comments
    393 } // end namespace clang
    394 
    395