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 void Comment::dump() const {
     36   // It is important that Comment::dump() is defined in a different TU than
     37   // Comment::dump(raw_ostream, SourceManager).  If both functions were defined
     38   // in CommentDumper.cpp, that object file would be removed by linker because
     39   // none of its functions are referenced by other object files, despite the
     40   // LLVM_ATTRIBUTE_USED.
     41   dump(llvm::errs(), NULL, NULL);
     42 }
     43 
     44 void Comment::dump(const ASTContext &Context) const {
     45   dump(llvm::errs(), &Context.getCommentCommandTraits(),
     46        &Context.getSourceManager());
     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 static inline bad implements_child_begin_end(
     59                       Comment::child_iterator (Comment::*)() const) {
     60   return bad();
     61 }
     62 
     63 #define ASSERT_IMPLEMENTS_child_begin(function) \
     64   (void) sizeof(good(implements_child_begin_end(function)))
     65 
     66 static inline void CheckCommentASTNodes() {
     67 #define ABSTRACT_COMMENT(COMMENT)
     68 #define COMMENT(CLASS, PARENT) \
     69   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \
     70   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);
     71 #include "clang/AST/CommentNodes.inc"
     72 #undef COMMENT
     73 #undef ABSTRACT_COMMENT
     74 }
     75 
     76 #undef ASSERT_IMPLEMENTS_child_begin
     77 
     78 } // end unnamed namespace
     79 
     80 Comment::child_iterator Comment::child_begin() 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_begin();
     87 #include "clang/AST/CommentNodes.inc"
     88 #undef COMMENT
     89 #undef ABSTRACT_COMMENT
     90   }
     91   llvm_unreachable("Unknown comment kind!");
     92 }
     93 
     94 Comment::child_iterator Comment::child_end() const {
     95   switch (getCommentKind()) {
     96   case NoCommentKind: llvm_unreachable("comment without a kind");
     97 #define ABSTRACT_COMMENT(COMMENT)
     98 #define COMMENT(CLASS, PARENT) \
     99   case CLASS##Kind: \
    100     return static_cast<const CLASS *>(this)->child_end();
    101 #include "clang/AST/CommentNodes.inc"
    102 #undef COMMENT
    103 #undef ABSTRACT_COMMENT
    104   }
    105   llvm_unreachable("Unknown comment kind!");
    106 }
    107 
    108 bool TextComment::isWhitespaceNoCache() const {
    109   for (StringRef::const_iterator I = Text.begin(), E = Text.end();
    110        I != E; ++I) {
    111     const char C = *I;
    112     if (C != ' ' && C != '\n' && C != '\r' &&
    113         C != '\t' && C != '\f' && C != '\v')
    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 const char *ParamCommandComment::getDirectionAsString(PassDirection D) {
    131   switch (D) {
    132   case ParamCommandComment::In:
    133     return "[in]";
    134   case ParamCommandComment::Out:
    135     return "[out]";
    136   case ParamCommandComment::InOut:
    137     return "[in,out]";
    138   }
    139   llvm_unreachable("unknown PassDirection");
    140 }
    141 
    142 void DeclInfo::fill() {
    143   assert(!IsFilled);
    144 
    145   // Set defaults.
    146   Kind = OtherKind;
    147   TemplateKind = NotTemplate;
    148   IsObjCMethod = false;
    149   IsInstanceMethod = false;
    150   IsClassMethod = false;
    151   ParamVars = ArrayRef<const ParmVarDecl *>();
    152   TemplateParameters = NULL;
    153 
    154   if (!ThisDecl) {
    155     // If there is no declaration, the defaults is our only guess.
    156     IsFilled = true;
    157     return;
    158   }
    159 
    160   Decl::Kind K = ThisDecl->getKind();
    161   switch (K) {
    162   default:
    163     // Defaults are should be good for declarations we don't handle explicitly.
    164     break;
    165   case Decl::Function:
    166   case Decl::CXXMethod:
    167   case Decl::CXXConstructor:
    168   case Decl::CXXDestructor:
    169   case Decl::CXXConversion: {
    170     const FunctionDecl *FD = cast<FunctionDecl>(ThisDecl);
    171     Kind = FunctionKind;
    172     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
    173                                               FD->getNumParams());
    174     ResultType = FD->getResultType();
    175     unsigned NumLists = FD->getNumTemplateParameterLists();
    176     if (NumLists != 0) {
    177       TemplateKind = TemplateSpecialization;
    178       TemplateParameters =
    179           FD->getTemplateParameterList(NumLists - 1);
    180     }
    181 
    182     if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
    183         K == Decl::CXXDestructor || K == Decl::CXXConversion) {
    184       const CXXMethodDecl *MD = cast<CXXMethodDecl>(ThisDecl);
    185       IsInstanceMethod = MD->isInstance();
    186       IsClassMethod = !IsInstanceMethod;
    187     }
    188     break;
    189   }
    190   case Decl::ObjCMethod: {
    191     const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(ThisDecl);
    192     Kind = FunctionKind;
    193     ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
    194                                               MD->param_size());
    195     ResultType = MD->getResultType();
    196     IsObjCMethod = true;
    197     IsInstanceMethod = MD->isInstanceMethod();
    198     IsClassMethod = !IsInstanceMethod;
    199     break;
    200   }
    201   case Decl::FunctionTemplate: {
    202     const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl);
    203     Kind = FunctionKind;
    204     TemplateKind = Template;
    205     const FunctionDecl *FD = FTD->getTemplatedDecl();
    206     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
    207                                               FD->getNumParams());
    208     ResultType = FD->getResultType();
    209     TemplateParameters = FTD->getTemplateParameters();
    210     break;
    211   }
    212   case Decl::ClassTemplate: {
    213     const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(ThisDecl);
    214     Kind = ClassKind;
    215     TemplateKind = Template;
    216     TemplateParameters = CTD->getTemplateParameters();
    217     break;
    218   }
    219   case Decl::ClassTemplatePartialSpecialization: {
    220     const ClassTemplatePartialSpecializationDecl *CTPSD =
    221         cast<ClassTemplatePartialSpecializationDecl>(ThisDecl);
    222     Kind = ClassKind;
    223     TemplateKind = TemplatePartialSpecialization;
    224     TemplateParameters = CTPSD->getTemplateParameters();
    225     break;
    226   }
    227   case Decl::ClassTemplateSpecialization:
    228     Kind = ClassKind;
    229     TemplateKind = TemplateSpecialization;
    230     break;
    231   case Decl::Record:
    232   case Decl::CXXRecord:
    233     Kind = ClassKind;
    234     break;
    235   case Decl::Var:
    236   case Decl::Field:
    237   case Decl::EnumConstant:
    238   case Decl::ObjCIvar:
    239   case Decl::ObjCAtDefsField:
    240     Kind = VariableKind;
    241     break;
    242   case Decl::Namespace:
    243     Kind = NamespaceKind;
    244     break;
    245   case Decl::Typedef: {
    246     Kind = TypedefKind;
    247     // If this is a typedef to something we consider a function, extract
    248     // arguments and return type.
    249     const TypedefDecl *TD = cast<TypedefDecl>(ThisDecl);
    250     const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
    251     if (!TSI)
    252       break;
    253     TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
    254     while (true) {
    255       TL = TL.IgnoreParens();
    256       // Look through typedefs.
    257       if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) {
    258         TSI = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo();
    259         if (TSI)
    260           break;
    261         TL = TSI->getTypeLoc().getUnqualifiedLoc();
    262         continue;
    263       }
    264       // Look through qualified types.
    265       if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
    266         TL = QualifiedTL->getUnqualifiedLoc();
    267         continue;
    268       }
    269       // Look through pointer types.
    270       if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) {
    271         TL = PointerTL->getPointeeLoc().getUnqualifiedLoc();
    272         continue;
    273       }
    274       if (BlockPointerTypeLoc *BlockPointerTL =
    275               dyn_cast<BlockPointerTypeLoc>(&TL)) {
    276         TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc();
    277         continue;
    278       }
    279       if (MemberPointerTypeLoc *MemberPointerTL =
    280               dyn_cast<MemberPointerTypeLoc>(&TL)) {
    281         TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc();
    282         continue;
    283       }
    284       // Is this a typedef for a function type?
    285       if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
    286         Kind = FunctionKind;
    287         ArrayRef<ParmVarDecl *> Params = FTL->getParams();
    288         ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
    289                                                   Params.size());
    290         ResultType = FTL->getResultLoc().getType();
    291         break;
    292       }
    293       break;
    294     }
    295     break;
    296   }
    297   case Decl::TypeAlias:
    298     Kind = TypedefKind;
    299     break;
    300   case Decl::TypeAliasTemplate: {
    301     const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl);
    302     Kind = TypedefKind;
    303     TemplateKind = Template;
    304     TemplateParameters = TAT->getTemplateParameters();
    305     break;
    306   }
    307   case Decl::Enum:
    308     Kind = EnumKind;
    309     break;
    310   }
    311 
    312   IsFilled = true;
    313 }
    314 
    315 } // end namespace comments
    316 } // end namespace clang
    317 
    318