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 = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
    161                                               FD->getNumParams());
    162     ReturnType = FD->getReturnType();
    163     unsigned NumLists = FD->getNumTemplateParameterLists();
    164     if (NumLists != 0) {
    165       TemplateKind = TemplateSpecialization;
    166       TemplateParameters =
    167           FD->getTemplateParameterList(NumLists - 1);
    168     }
    169 
    170     if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
    171         K == Decl::CXXDestructor || K == Decl::CXXConversion) {
    172       const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
    173       IsInstanceMethod = MD->isInstance();
    174       IsClassMethod = !IsInstanceMethod;
    175     }
    176     break;
    177   }
    178   case Decl::ObjCMethod: {
    179     const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
    180     Kind = FunctionKind;
    181     ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
    182                                               MD->param_size());
    183     ReturnType = MD->getReturnType();
    184     IsObjCMethod = true;
    185     IsInstanceMethod = MD->isInstanceMethod();
    186     IsClassMethod = !IsInstanceMethod;
    187     break;
    188   }
    189   case Decl::FunctionTemplate: {
    190     const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
    191     Kind = FunctionKind;
    192     TemplateKind = Template;
    193     const FunctionDecl *FD = FTD->getTemplatedDecl();
    194     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
    195                                               FD->getNumParams());
    196     ReturnType = FD->getReturnType();
    197     TemplateParameters = FTD->getTemplateParameters();
    198     break;
    199   }
    200   case Decl::ClassTemplate: {
    201     const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
    202     Kind = ClassKind;
    203     TemplateKind = Template;
    204     TemplateParameters = CTD->getTemplateParameters();
    205     break;
    206   }
    207   case Decl::ClassTemplatePartialSpecialization: {
    208     const ClassTemplatePartialSpecializationDecl *CTPSD =
    209         cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
    210     Kind = ClassKind;
    211     TemplateKind = TemplatePartialSpecialization;
    212     TemplateParameters = CTPSD->getTemplateParameters();
    213     break;
    214   }
    215   case Decl::ClassTemplateSpecialization:
    216     Kind = ClassKind;
    217     TemplateKind = TemplateSpecialization;
    218     break;
    219   case Decl::Record:
    220   case Decl::CXXRecord:
    221     Kind = ClassKind;
    222     break;
    223   case Decl::Var:
    224   case Decl::Field:
    225   case Decl::EnumConstant:
    226   case Decl::ObjCIvar:
    227   case Decl::ObjCAtDefsField:
    228     Kind = VariableKind;
    229     break;
    230   case Decl::Namespace:
    231     Kind = NamespaceKind;
    232     break;
    233   case Decl::Typedef: {
    234     Kind = TypedefKind;
    235     // If this is a typedef to something we consider a function, extract
    236     // arguments and return type.
    237     const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl);
    238     const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
    239     if (!TSI)
    240       break;
    241     TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
    242     while (true) {
    243       TL = TL.IgnoreParens();
    244       // Look through qualified types.
    245       if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {
    246         TL = QualifiedTL.getUnqualifiedLoc();
    247         continue;
    248       }
    249       // Look through pointer types.
    250       if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) {
    251         TL = PointerTL.getPointeeLoc().getUnqualifiedLoc();
    252         continue;
    253       }
    254       // Look through reference types.
    255       if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>()) {
    256         TL = ReferenceTL.getPointeeLoc().getUnqualifiedLoc();
    257         continue;
    258       }
    259       // Look through adjusted types.
    260       if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) {
    261         TL = ATL.getOriginalLoc();
    262         continue;
    263       }
    264       if (BlockPointerTypeLoc BlockPointerTL =
    265               TL.getAs<BlockPointerTypeLoc>()) {
    266         TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
    267         continue;
    268       }
    269       if (MemberPointerTypeLoc MemberPointerTL =
    270               TL.getAs<MemberPointerTypeLoc>()) {
    271         TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
    272         continue;
    273       }
    274       if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) {
    275         TL = ETL.getNamedTypeLoc();
    276         continue;
    277       }
    278       // Is this a typedef for a function type?
    279       if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
    280         Kind = FunctionKind;
    281         ArrayRef<ParmVarDecl *> Params = FTL.getParams();
    282         ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
    283                                                   Params.size());
    284         ReturnType = FTL.getReturnLoc().getType();
    285         break;
    286       }
    287       if (TemplateSpecializationTypeLoc STL =
    288               TL.getAs<TemplateSpecializationTypeLoc>()) {
    289         // If we have a typedef to a template specialization with exactly one
    290         // template argument of a function type, this looks like std::function,
    291         // boost::function, or other function wrapper.  Treat these typedefs as
    292         // functions.
    293         if (STL.getNumArgs() != 1)
    294           break;
    295         TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0);
    296         if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type)
    297           break;
    298         TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo();
    299         TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc();
    300         if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
    301           Kind = FunctionKind;
    302           ArrayRef<ParmVarDecl *> Params = FTL.getParams();
    303           ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
    304                                                     Params.size());
    305           ReturnType = FTL.getReturnLoc().getType();
    306         }
    307         break;
    308       }
    309       break;
    310     }
    311     break;
    312   }
    313   case Decl::TypeAlias:
    314     Kind = TypedefKind;
    315     break;
    316   case Decl::TypeAliasTemplate: {
    317     const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
    318     Kind = TypedefKind;
    319     TemplateKind = Template;
    320     TemplateParameters = TAT->getTemplateParameters();
    321     break;
    322   }
    323   case Decl::Enum:
    324     Kind = EnumKind;
    325     break;
    326   }
    327 
    328   IsFilled = true;
    329 }
    330 
    331 StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
    332   assert(isParamIndexValid());
    333   if (isVarArgParam())
    334     return "...";
    335   return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
    336 }
    337 
    338 StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
    339   assert(isPositionValid());
    340   const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
    341   for (unsigned i = 0, e = getDepth(); i != e; ++i) {
    342     if (i == e-1)
    343       return TPL->getParam(getIndex(i))->getName();
    344     const NamedDecl *Param = TPL->getParam(getIndex(i));
    345     if (const TemplateTemplateParmDecl *TTP =
    346           dyn_cast<TemplateTemplateParmDecl>(Param))
    347       TPL = TTP->getTemplateParameters();
    348   }
    349   return "";
    350 }
    351 
    352 } // end namespace comments
    353 } // end namespace clang
    354 
    355