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