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 "llvm/Support/ErrorHandling.h"
     16 #include "llvm/Support/raw_ostream.h"
     17 
     18 namespace clang {
     19 namespace comments {
     20 
     21 const char *Comment::getCommentKindName() const {
     22   switch (getCommentKind()) {
     23   case NoCommentKind: return "NoCommentKind";
     24 #define ABSTRACT_COMMENT(COMMENT)
     25 #define COMMENT(CLASS, PARENT) \
     26   case CLASS##Kind: \
     27     return #CLASS;
     28 #include "clang/AST/CommentNodes.inc"
     29 #undef COMMENT
     30 #undef ABSTRACT_COMMENT
     31   }
     32   llvm_unreachable("Unknown comment kind!");
     33 }
     34 
     35 namespace {
     36 struct good {};
     37 struct bad {};
     38 
     39 template <typename T>
     40 good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
     41   return good();
     42 }
     43 
     44 static inline bad implements_child_begin_end(
     45                       Comment::child_iterator (Comment::*)() const) {
     46   return bad();
     47 }
     48 
     49 #define ASSERT_IMPLEMENTS_child_begin(function) \
     50   (void) sizeof(good(implements_child_begin_end(function)))
     51 
     52 static inline void CheckCommentASTNodes() {
     53 #define ABSTRACT_COMMENT(COMMENT)
     54 #define COMMENT(CLASS, PARENT) \
     55   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \
     56   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);
     57 #include "clang/AST/CommentNodes.inc"
     58 #undef COMMENT
     59 #undef ABSTRACT_COMMENT
     60 }
     61 
     62 #undef ASSERT_IMPLEMENTS_child_begin
     63 
     64 } // end unnamed namespace
     65 
     66 Comment::child_iterator Comment::child_begin() const {
     67   switch (getCommentKind()) {
     68   case NoCommentKind: llvm_unreachable("comment without a kind");
     69 #define ABSTRACT_COMMENT(COMMENT)
     70 #define COMMENT(CLASS, PARENT) \
     71   case CLASS##Kind: \
     72     return static_cast<const CLASS *>(this)->child_begin();
     73 #include "clang/AST/CommentNodes.inc"
     74 #undef COMMENT
     75 #undef ABSTRACT_COMMENT
     76   }
     77   llvm_unreachable("Unknown comment kind!");
     78 }
     79 
     80 Comment::child_iterator Comment::child_end() const {
     81   switch (getCommentKind()) {
     82   case NoCommentKind: llvm_unreachable("comment without a kind");
     83 #define ABSTRACT_COMMENT(COMMENT)
     84 #define COMMENT(CLASS, PARENT) \
     85   case CLASS##Kind: \
     86     return static_cast<const CLASS *>(this)->child_end();
     87 #include "clang/AST/CommentNodes.inc"
     88 #undef COMMENT
     89 #undef ABSTRACT_COMMENT
     90   }
     91   llvm_unreachable("Unknown comment kind!");
     92 }
     93 
     94 bool TextComment::isWhitespaceNoCache() const {
     95   for (StringRef::const_iterator I = Text.begin(), E = Text.end();
     96        I != E; ++I) {
     97     const char C = *I;
     98     if (C != ' ' && C != '\n' && C != '\r' &&
     99         C != '\t' && C != '\f' && C != '\v')
    100       return false;
    101   }
    102   return true;
    103 }
    104 
    105 bool ParagraphComment::isWhitespaceNoCache() const {
    106   for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
    107     if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
    108       if (!TC->isWhitespace())
    109         return false;
    110     } else
    111       return false;
    112   }
    113   return true;
    114 }
    115 
    116 const char *ParamCommandComment::getDirectionAsString(PassDirection D) {
    117   switch (D) {
    118   case ParamCommandComment::In:
    119     return "[in]";
    120   case ParamCommandComment::Out:
    121     return "[out]";
    122   case ParamCommandComment::InOut:
    123     return "[in,out]";
    124   }
    125   llvm_unreachable("unknown PassDirection");
    126 }
    127 
    128 void DeclInfo::fill() {
    129   assert(!IsFilled);
    130 
    131   // Set defaults.
    132   Kind = OtherKind;
    133   TemplateKind = NotTemplate;
    134   IsObjCMethod = false;
    135   IsInstanceMethod = false;
    136   IsClassMethod = false;
    137   ParamVars = None;
    138   TemplateParameters = NULL;
    139 
    140   if (!CommentDecl) {
    141     // If there is no declaration, the defaults is our only guess.
    142     IsFilled = true;
    143     return;
    144   }
    145   CurrentDecl = CommentDecl;
    146 
    147   Decl::Kind K = CommentDecl->getKind();
    148   switch (K) {
    149   default:
    150     // Defaults are should be good for declarations we don't handle explicitly.
    151     break;
    152   case Decl::Function:
    153   case Decl::CXXMethod:
    154   case Decl::CXXConstructor:
    155   case Decl::CXXDestructor:
    156   case Decl::CXXConversion: {
    157     const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
    158     Kind = FunctionKind;
    159     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
    160                                               FD->getNumParams());
    161     ResultType = FD->getResultType();
    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 = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
    181                                               MD->param_size());
    182     ResultType = MD->getResultType();
    183     IsObjCMethod = true;
    184     IsInstanceMethod = MD->isInstanceMethod();
    185     IsClassMethod = !IsInstanceMethod;
    186     break;
    187   }
    188   case Decl::FunctionTemplate: {
    189     const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
    190     Kind = FunctionKind;
    191     TemplateKind = Template;
    192     const FunctionDecl *FD = FTD->getTemplatedDecl();
    193     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
    194                                               FD->getNumParams());
    195     ResultType = FD->getResultType();
    196     TemplateParameters = FTD->getTemplateParameters();
    197     break;
    198   }
    199   case Decl::ClassTemplate: {
    200     const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
    201     Kind = ClassKind;
    202     TemplateKind = Template;
    203     TemplateParameters = CTD->getTemplateParameters();
    204     break;
    205   }
    206   case Decl::ClassTemplatePartialSpecialization: {
    207     const ClassTemplatePartialSpecializationDecl *CTPSD =
    208         cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
    209     Kind = ClassKind;
    210     TemplateKind = TemplatePartialSpecialization;
    211     TemplateParameters = CTPSD->getTemplateParameters();
    212     break;
    213   }
    214   case Decl::ClassTemplateSpecialization:
    215     Kind = ClassKind;
    216     TemplateKind = TemplateSpecialization;
    217     break;
    218   case Decl::Record:
    219   case Decl::CXXRecord:
    220     Kind = ClassKind;
    221     break;
    222   case Decl::Var:
    223   case Decl::Field:
    224   case Decl::EnumConstant:
    225   case Decl::ObjCIvar:
    226   case Decl::ObjCAtDefsField:
    227     Kind = VariableKind;
    228     break;
    229   case Decl::Namespace:
    230     Kind = NamespaceKind;
    231     break;
    232   case Decl::Typedef: {
    233     Kind = TypedefKind;
    234     // If this is a typedef to something we consider a function, extract
    235     // arguments and return type.
    236     const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl);
    237     const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
    238     if (!TSI)
    239       break;
    240     TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
    241     while (true) {
    242       TL = TL.IgnoreParens();
    243       // Look through qualified types.
    244       if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {
    245         TL = QualifiedTL.getUnqualifiedLoc();
    246         continue;
    247       }
    248       // Look through pointer types.
    249       if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) {
    250         TL = PointerTL.getPointeeLoc().getUnqualifiedLoc();
    251         continue;
    252       }
    253       if (BlockPointerTypeLoc BlockPointerTL =
    254               TL.getAs<BlockPointerTypeLoc>()) {
    255         TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
    256         continue;
    257       }
    258       if (MemberPointerTypeLoc MemberPointerTL =
    259               TL.getAs<MemberPointerTypeLoc>()) {
    260         TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
    261         continue;
    262       }
    263       // Is this a typedef for a function type?
    264       if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
    265         Kind = FunctionKind;
    266         ArrayRef<ParmVarDecl *> Params = FTL.getParams();
    267         ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
    268                                                   Params.size());
    269         ResultType = FTL.getResultLoc().getType();
    270         break;
    271       }
    272       break;
    273     }
    274     break;
    275   }
    276   case Decl::TypeAlias:
    277     Kind = TypedefKind;
    278     break;
    279   case Decl::TypeAliasTemplate: {
    280     const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
    281     Kind = TypedefKind;
    282     TemplateKind = Template;
    283     TemplateParameters = TAT->getTemplateParameters();
    284     break;
    285   }
    286   case Decl::Enum:
    287     Kind = EnumKind;
    288     break;
    289   }
    290 
    291   IsFilled = true;
    292 }
    293 
    294 StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
    295   assert(isParamIndexValid());
    296   if (isVarArgParam())
    297     return "...";
    298   return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
    299 }
    300 
    301 StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
    302   assert(isPositionValid());
    303   const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
    304   for (unsigned i = 0, e = getDepth(); i != e; ++i) {
    305     if (i == e-1)
    306       return TPL->getParam(getIndex(i))->getName();
    307     const NamedDecl *Param = TPL->getParam(getIndex(i));
    308     if (const TemplateTemplateParmDecl *TTP =
    309           dyn_cast<TemplateTemplateParmDecl>(Param))
    310       TPL = TTP->getTemplateParameters();
    311   }
    312   return "";
    313 }
    314 
    315 } // end namespace comments
    316 } // end namespace clang
    317 
    318